blob: 18d6c0338f05860fd54c372532baf836842257bd [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <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"
ager@chromium.org7c537e22008-10-16 08:43:32 +000045#include "smart-pointer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47namespace v8 { namespace internal {
48
49
50#define RUNTIME_ASSERT(value) do { \
51 if (!(value)) return IllegalOperation(); \
52} while (false)
53
54// Cast the given object to a value of the specified type and store
55// it in a variable with the given name. If the object is not of the
56// expected type call IllegalOperation and return.
57#define CONVERT_CHECKED(Type, name, obj) \
58 RUNTIME_ASSERT(obj->Is##Type()); \
59 Type* name = Type::cast(obj);
60
61#define CONVERT_ARG_CHECKED(Type, name, index) \
62 RUNTIME_ASSERT(args[index]->Is##Type()); \
63 Handle<Type> name = args.at<Type>(index);
64
kasper.lundbd3ec4e2008-07-09 11:06:54 +000065// Cast the given object to a boolean and store it in a variable with
66// the given name. If the object is not a boolean call IllegalOperation
67// and return.
68#define CONVERT_BOOLEAN_CHECKED(name, obj) \
69 RUNTIME_ASSERT(obj->IsBoolean()); \
70 bool name = (obj)->IsTrue();
71
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072// Cast the given object to a double and store it in a variable with
73// the given name. If the object is not a number (as opposed to
74// the number not-a-number) call IllegalOperation and return.
75#define CONVERT_DOUBLE_CHECKED(name, obj) \
76 RUNTIME_ASSERT(obj->IsNumber()); \
77 double name = (obj)->Number();
78
79// Call the specified converter on the object *comand store the result in
80// a variable of the specified type with the given name. If the
81// object is not a Number call IllegalOperation and return.
82#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
83 RUNTIME_ASSERT(obj->IsNumber()); \
84 type name = NumberTo##Type(obj);
85
86// Non-reentrant string buffer for efficient general use in this file.
87static StaticResource<StringInputBuffer> string_input_buffer;
88
89
90static Object* IllegalOperation() {
91 return Top::Throw(Heap::illegal_access_symbol());
92}
93
94
95static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
96 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000097 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098}
99
100
ager@chromium.org236ad962008-09-25 09:45:57 +0000101static Handle<Map> ComputeObjectLiteralMap(
102 Handle<Context> context,
103 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000104 bool* is_result_from_cache) {
ager@chromium.org32912102009-01-16 10:38:43 +0000105 int number_of_properties = constant_properties->length() / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000106 if (FLAG_canonicalize_object_literal_maps) {
107 // First find prefix of consecutive symbol keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000108 int number_of_symbol_keys = 0;
109 while ((number_of_symbol_keys < number_of_properties) &&
110 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
111 number_of_symbol_keys++;
112 }
113 // Based on the number of prefix symbols key we decide whether
114 // to use the map cache in the global context.
115 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000116 if ((number_of_symbol_keys == number_of_properties) &&
117 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000118 // Create the fixed array with the key.
119 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
120 for (int i = 0; i < number_of_symbol_keys; i++) {
121 keys->set(i, constant_properties->get(i*2));
122 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000123 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000124 return Factory::ObjectLiteralMapFromCache(context, keys);
125 }
126 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000127 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000128 return Factory::CopyMap(
129 Handle<Map>(context->object_function()->initial_map()),
130 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000131}
132
133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
135 HandleScope scope;
136 ASSERT(args.length() == 3);
137 // Copy the arguments.
138 Handle<FixedArray> literals = args.at<FixedArray>(0);
139 int literals_index = Smi::cast(args[1])->value();
140 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000141
142 // Get the global context from the literals array. This is the
143 // context in which the function was created and we use the object
144 // function from this context to create the object literal. We do
145 // not use the object function from the current global context
146 // because this might be the object function from another context
147 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000148 Handle<Context> context =
149 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
150
151 bool is_result_from_cache;
152 Handle<Map> map = ComputeObjectLiteralMap(context,
153 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000154 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155
ager@chromium.org236ad962008-09-25 09:45:57 +0000156 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
ager@chromium.org32912102009-01-16 10:38:43 +0000157 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000159 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
160 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161 for (int index = 0; index < length; index +=2) {
162 Handle<Object> key(constant_properties->get(index+0));
163 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000164 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 uint32_t element_index = 0;
166 if (key->IsSymbol()) {
167 // If key is a symbol it is not an array element.
168 Handle<String> name(String::cast(*key));
169 ASSERT(!name->AsArrayIndex(&element_index));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000170 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 } else if (Array::IndexFromObject(*key, &element_index)) {
172 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000173 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 } else {
175 // Non-uint32 number.
176 ASSERT(key->IsNumber());
177 double num = key->Number();
178 char arr[100];
179 Vector<char> buffer(arr, ARRAY_SIZE(arr));
180 const char* str = DoubleToCString(num, buffer);
181 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000182 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000184 // If setting the property on the boilerplate throws an
185 // exception, the exception is converted to an empty handle in
186 // the handle based operations. In that case, we need to
187 // convert back to an exception.
188 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 }
190 }
191
192 // Update the functions literal and return the boilerplate.
193 literals->set(literals_index, *boilerplate);
194
195 return *boilerplate;
196}
197
198
199static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000200 // Takes a FixedArray of elements containing the literal elements of
201 // the array literal and produces JSArray with those elements.
202 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000203 // which contains the context from which to get the Array function
204 // to use for creating the array literal.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000205 ASSERT(args.length() == 2);
206 CONVERT_CHECKED(FixedArray, elements, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207 CONVERT_CHECKED(FixedArray, literals, args[1]);
ager@chromium.org236ad962008-09-25 09:45:57 +0000208 JSFunction* constructor =
209 JSFunction::GlobalContextFromLiterals(literals)->array_function();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 // Create the JSArray.
211 Object* object = Heap::AllocateJSObject(constructor);
212 if (object->IsFailure()) return object;
213
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000214 // Copy the elements.
215 Object* content = elements->Copy();
216 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217
218 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000219 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000220 return object;
221}
222
223
ager@chromium.org32912102009-01-16 10:38:43 +0000224static Object* Runtime_CreateCatchExtensionObject(Arguments args) {
225 ASSERT(args.length() == 2);
226 CONVERT_CHECKED(String, key, args[0]);
227 Object* value = args[1];
228 // Create a catch context extension object.
229 JSFunction* constructor =
230 Top::context()->global_context()->context_extension_function();
231 Object* object = Heap::AllocateJSObject(constructor);
232 if (object->IsFailure()) return object;
233 // Assign the exception value to the catch variable and make sure
234 // that the catch variable is DontDelete.
235 value = JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
236 if (value->IsFailure()) return value;
237 return object;
238}
239
240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000241static Object* Runtime_ClassOf(Arguments args) {
242 NoHandleAllocation ha;
243 ASSERT(args.length() == 1);
244 Object* obj = args[0];
245 if (!obj->IsJSObject()) return Heap::null_value();
246 return JSObject::cast(obj)->class_name();
247}
248
ager@chromium.org7c537e22008-10-16 08:43:32 +0000249
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000250static Object* Runtime_HasStringClass(Arguments args) {
251 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000252}
253
254
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000255static Object* Runtime_HasDateClass(Arguments args) {
256 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000257}
258
259
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000260static Object* Runtime_HasArrayClass(Arguments args) {
261 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
262}
263
264
265static Object* Runtime_HasFunctionClass(Arguments args) {
266 return Heap::ToBoolean(
267 args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
268}
269
270
271static Object* Runtime_HasNumberClass(Arguments args) {
272 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
273}
274
275
276static Object* Runtime_HasBooleanClass(Arguments args) {
277 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
278}
279
280
281static Object* Runtime_HasArgumentsClass(Arguments args) {
282 return Heap::ToBoolean(
283 args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
284}
285
286
287static Object* Runtime_HasRegExpClass(Arguments args) {
288 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000289}
290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291
292static Object* Runtime_IsInPrototypeChain(Arguments args) {
293 NoHandleAllocation ha;
294 ASSERT(args.length() == 2);
295 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
296 Object* O = args[0];
297 Object* V = args[1];
298 while (true) {
299 Object* prototype = V->GetPrototype();
300 if (prototype->IsNull()) return Heap::false_value();
301 if (O == prototype) return Heap::true_value();
302 V = prototype;
303 }
304}
305
306
307static Object* Runtime_IsConstructCall(Arguments args) {
308 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000309 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310 JavaScriptFrameIterator it;
311 return Heap::ToBoolean(it.frame()->IsConstructor());
312}
313
314
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315static Object* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000316 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
319 Handle<JSRegExp> re(raw_re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 CONVERT_CHECKED(String, raw_pattern, args[1]);
321 Handle<String> pattern(raw_pattern);
322 CONVERT_CHECKED(String, raw_flags, args[2]);
323 Handle<String> flags(raw_flags);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000324 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
325 if (result.is_null()) return Failure::Exception();
326 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327}
328
329
330static Object* Runtime_CreateApiFunction(Arguments args) {
331 HandleScope scope;
332 ASSERT(args.length() == 1);
333 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
334 Handle<FunctionTemplateInfo> data(raw_data);
335 return *Factory::CreateApiFunction(data);
336}
337
338
339static Object* Runtime_IsTemplate(Arguments args) {
340 ASSERT(args.length() == 1);
341 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000342 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 return Heap::ToBoolean(result);
344}
345
346
347static Object* Runtime_GetTemplateField(Arguments args) {
348 ASSERT(args.length() == 2);
349 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000351 int index = field->value();
352 int offset = index * kPointerSize + HeapObject::kHeaderSize;
353 InstanceType type = templ->map()->instance_type();
354 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
355 type == OBJECT_TEMPLATE_INFO_TYPE);
356 RUNTIME_ASSERT(offset > 0);
357 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
358 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
359 } else {
360 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
361 }
362 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363}
364
365
ager@chromium.org870a0b62008-11-04 11:43:05 +0000366static Object* Runtime_DisableAccessChecks(Arguments args) {
367 ASSERT(args.length() == 1);
368 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000369 Map* old_map = object->map();
370 bool needs_access_checks = old_map->is_access_check_needed();
371 if (needs_access_checks) {
372 // Copy map so it won't interfere constructor's initial map.
373 Object* new_map = old_map->CopyDropTransitions();
374 if (new_map->IsFailure()) return new_map;
375
376 Map::cast(new_map)->set_is_access_check_needed(false);
377 object->set_map(Map::cast(new_map));
378 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000379 return needs_access_checks ? Heap::true_value() : Heap::false_value();
380}
381
382
383static Object* Runtime_EnableAccessChecks(Arguments args) {
384 ASSERT(args.length() == 1);
385 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000386 Map* old_map = object->map();
387 if (!old_map->is_access_check_needed()) {
388 // Copy map so it won't interfere constructor's initial map.
389 Object* new_map = old_map->CopyDropTransitions();
390 if (new_map->IsFailure()) return new_map;
391
392 Map::cast(new_map)->set_is_access_check_needed(true);
393 object->set_map(Map::cast(new_map));
394 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000395 return Heap::undefined_value();
396}
397
398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
400 HandleScope scope;
401 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
402 Handle<Object> args[2] = { type_handle, name };
403 Handle<Object> error =
404 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
405 return Top::Throw(*error);
406}
407
408
409static Object* Runtime_DeclareGlobals(Arguments args) {
410 HandleScope scope;
411 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
412
413 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
414 Handle<Context> context = args.at<Context>(1);
415 bool is_eval = Smi::cast(args[2])->value() == 1;
416
417 // Compute the property attributes. According to ECMA-262, section
418 // 13, page 71, the property must be read-only and
419 // non-deletable. However, neither SpiderMonkey nor KJS creates the
420 // property as read-only, so we don't either.
421 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
422
423 // Only optimize the object if we intend to add more than 5 properties.
424 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
425
426 // Traverse the name/value pairs and set the properties.
427 int length = pairs->length();
428 for (int i = 0; i < length; i += 2) {
429 HandleScope scope;
430 Handle<String> name(String::cast(pairs->get(i)));
431 Handle<Object> value(pairs->get(i + 1));
432
433 // We have to declare a global const property. To capture we only
434 // assign to it when evaluating the assignment for "const x =
435 // <expr>" the initial value is the hole.
436 bool is_const_property = value->IsTheHole();
437
438 if (value->IsUndefined() || is_const_property) {
439 // Lookup the property in the global object, and don't set the
440 // value of the variable if the property is already there.
441 LookupResult lookup;
442 global->Lookup(*name, &lookup);
443 if (lookup.IsProperty()) {
444 // Determine if the property is local by comparing the holder
445 // against the global object. The information will be used to
446 // avoid throwing re-declaration errors when declaring
447 // variables or constants that exist in the prototype chain.
448 bool is_local = (*global == lookup.holder());
449 // Get the property attributes and determine if the property is
450 // read-only.
451 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
452 bool is_read_only = (attributes & READ_ONLY) != 0;
453 if (lookup.type() == INTERCEPTOR) {
454 // If the interceptor says the property is there, we
455 // just return undefined without overwriting the property.
456 // Otherwise, we continue to setting the property.
457 if (attributes != ABSENT) {
458 // Check if the existing property conflicts with regards to const.
459 if (is_local && (is_read_only || is_const_property)) {
460 const char* type = (is_read_only) ? "const" : "var";
461 return ThrowRedeclarationError(type, name);
462 };
463 // The property already exists without conflicting: Go to
464 // the next declaration.
465 continue;
466 }
467 // Fall-through and introduce the absent property by using
468 // SetProperty.
469 } else {
470 if (is_local && (is_read_only || is_const_property)) {
471 const char* type = (is_read_only) ? "const" : "var";
472 return ThrowRedeclarationError(type, name);
473 }
474 // The property already exists without conflicting: Go to
475 // the next declaration.
476 continue;
477 }
478 }
479 } else {
480 // Copy the function and update its context. Use it as value.
481 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
482 Handle<JSFunction> function =
483 Factory::NewFunctionFromBoilerplate(boilerplate, context);
484 value = function;
485 }
486
487 LookupResult lookup;
488 global->LocalLookup(*name, &lookup);
489
490 PropertyAttributes attributes = is_const_property
491 ? static_cast<PropertyAttributes>(base | READ_ONLY)
492 : base;
493
494 if (lookup.IsProperty()) {
495 // There's a local property that we need to overwrite because
496 // we're either declaring a function or there's an interceptor
497 // that claims the property is absent.
498
499 // Check for conflicting re-declarations. We cannot have
500 // conflicting types in case of intercepted properties because
501 // they are absent.
502 if (lookup.type() != INTERCEPTOR &&
503 (lookup.IsReadOnly() || is_const_property)) {
504 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
505 return ThrowRedeclarationError(type, name);
506 }
507 SetProperty(global, name, value, attributes);
508 } else {
509 // If a property with this name does not already exist on the
510 // global object add the property locally. We take special
511 // precautions to always add it as a local property even in case
512 // of callbacks in the prototype chain (this rules out using
513 // SetProperty). Also, we must use the handle-based version to
514 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000515 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516 }
517 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000518
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519 return Heap::undefined_value();
520}
521
522
523static Object* Runtime_DeclareContextSlot(Arguments args) {
524 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000525 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526
ager@chromium.org7c537e22008-10-16 08:43:32 +0000527 CONVERT_ARG_CHECKED(Context, context, 0);
528 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000530 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000532 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533
534 // Declarations are always done in the function context.
535 context = Handle<Context>(context->fcontext());
536
537 int index;
538 PropertyAttributes attributes;
539 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000540 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000541 context->Lookup(name, flags, &index, &attributes);
542
543 if (attributes != ABSENT) {
544 // The name was declared before; check for conflicting
545 // re-declarations: This is similar to the code in parser.cc in
546 // the AstBuildingParser::Declare function.
547 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
548 // Functions are not read-only.
549 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
550 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
551 return ThrowRedeclarationError(type, name);
552 }
553
554 // Initialize it if necessary.
555 if (*initial_value != NULL) {
556 if (index >= 0) {
557 // The variable or constant context slot should always be in
558 // the function context; not in any outer context nor in the
559 // arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000560 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561 if (((attributes & READ_ONLY) == 0) ||
562 context->get(index)->IsTheHole()) {
563 context->set(index, *initial_value);
564 }
565 } else {
566 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000567 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 SetProperty(context_ext, name, initial_value, mode);
569 }
570 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000573 // The property is not in the function context. It needs to be
574 // "declared" in the function context's extension context, or in the
575 // global context.
576 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000577 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000578 // The function context's extension context exists - use it.
579 context_ext = Handle<JSObject>(context->extension());
580 } else {
581 // The function context's extension context does not exists - allocate
582 // it.
583 context_ext = Factory::NewJSObject(Top::context_extension_function());
584 // And store it in the extension slot.
585 context->set_extension(*context_ext);
586 }
587 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588
ager@chromium.org7c537e22008-10-16 08:43:32 +0000589 // Declare the property by setting it to the initial value if provided,
590 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
591 // constant declarations).
592 ASSERT(!context_ext->HasLocalProperty(*name));
593 Handle<Object> value(Heap::undefined_value());
594 if (*initial_value != NULL) value = initial_value;
595 SetProperty(context_ext, name, value, mode);
596 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
597 }
598
599 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600}
601
602
603static Object* Runtime_InitializeVarGlobal(Arguments args) {
604 NoHandleAllocation nha;
605
606 // Determine if we need to assign to the variable if it already
607 // exists (based on the number of arguments).
608 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
609 bool assign = args.length() == 2;
610
611 CONVERT_ARG_CHECKED(String, name, 0);
612 GlobalObject* global = Top::context()->global();
613
614 // According to ECMA-262, section 12.2, page 62, the property must
615 // not be deletable.
616 PropertyAttributes attributes = DONT_DELETE;
617
618 // Lookup the property locally in the global object. If it isn't
619 // there, we add the property and take special precautions to always
620 // add it as a local property even in case of callbacks in the
621 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000622 // We have IgnoreAttributesAndSetLocalProperty for this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 LookupResult lookup;
624 global->LocalLookup(*name, &lookup);
625 if (!lookup.IsProperty()) {
626 Object* value = (assign) ? args[1] : Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000627 return global->IgnoreAttributesAndSetLocalProperty(*name,
628 value,
629 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 }
631
632 // Determine if this is a redeclaration of something read-only.
633 if (lookup.IsReadOnly()) {
634 return ThrowRedeclarationError("const", name);
635 }
636
637 // Determine if this is a redeclaration of an intercepted read-only
638 // property and figure out if the property exists at all.
639 bool found = true;
640 PropertyType type = lookup.type();
641 if (type == INTERCEPTOR) {
642 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
643 if (intercepted == ABSENT) {
644 // The interceptor claims the property isn't there. We need to
645 // make sure to introduce it.
646 found = false;
647 } else if ((intercepted & READ_ONLY) != 0) {
648 // The property is present, but read-only. Since we're trying to
649 // overwrite it with a variable declaration we must throw a
650 // re-declaration error.
651 return ThrowRedeclarationError("const", name);
652 }
653 // Restore global object from context (in case of GC).
654 global = Top::context()->global();
655 }
656
657 if (found && !assign) {
658 // The global property is there and we're not assigning any value
659 // to it. Just return.
660 return Heap::undefined_value();
661 }
662
663 // Assign the value (or undefined) to the property.
664 Object* value = (assign) ? args[1] : Heap::undefined_value();
665 return global->SetProperty(&lookup, *name, value, attributes);
666}
667
668
669static Object* Runtime_InitializeConstGlobal(Arguments args) {
670 // All constants are declared with an initial value. The name
671 // of the constant is the first argument and the initial value
672 // is the second.
673 RUNTIME_ASSERT(args.length() == 2);
674 CONVERT_ARG_CHECKED(String, name, 0);
675 Handle<Object> value = args.at<Object>(1);
676
677 // Get the current global object from top.
678 GlobalObject* global = Top::context()->global();
679
680 // According to ECMA-262, section 12.2, page 62, the property must
681 // not be deletable. Since it's a const, it must be READ_ONLY too.
682 PropertyAttributes attributes =
683 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
684
685 // Lookup the property locally in the global object. If it isn't
686 // there, we add the property and take special precautions to always
687 // add it as a local property even in case of callbacks in the
688 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000689 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000690 LookupResult lookup;
691 global->LocalLookup(*name, &lookup);
692 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000693 return global->IgnoreAttributesAndSetLocalProperty(*name,
694 *value,
695 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 }
697
698 // Determine if this is a redeclaration of something not
699 // read-only. In case the result is hidden behind an interceptor we
700 // need to ask it for the property attributes.
701 if (!lookup.IsReadOnly()) {
702 if (lookup.type() != INTERCEPTOR) {
703 return ThrowRedeclarationError("var", name);
704 }
705
706 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
707
708 // Throw re-declaration error if the intercepted property is present
709 // but not read-only.
710 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
711 return ThrowRedeclarationError("var", name);
712 }
713
714 // Restore global object from context (in case of GC) and continue
715 // with setting the value because the property is either absent or
716 // read-only. We also have to do redo the lookup.
717 global = Top::context()->global();
718
719 // BUG 1213579: Handle the case where we have to set a read-only
720 // property through an interceptor and only do it if it's
721 // uninitialized, e.g. the hole. Nirk...
722 global->SetProperty(*name, *value, attributes);
723 return *value;
724 }
725
726 // Set the value, but only we're assigning the initial value to a
727 // constant. For now, we determine this by checking if the
728 // current value is the hole.
729 PropertyType type = lookup.type();
730 if (type == FIELD) {
731 FixedArray* properties = global->properties();
732 int index = lookup.GetFieldIndex();
733 if (properties->get(index)->IsTheHole()) {
734 properties->set(index, *value);
735 }
736 } else if (type == NORMAL) {
737 Dictionary* dictionary = global->property_dictionary();
738 int entry = lookup.GetDictionaryEntry();
739 if (dictionary->ValueAt(entry)->IsTheHole()) {
740 dictionary->ValueAtPut(entry, *value);
741 }
742 } else {
743 // Ignore re-initialization of constants that have already been
744 // assigned a function value.
745 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
746 }
747
748 // Use the set value as the result of the operation.
749 return *value;
750}
751
752
753static Object* Runtime_InitializeConstContextSlot(Arguments args) {
754 HandleScope scope;
755 ASSERT(args.length() == 3);
756
757 Handle<Object> value(args[0]);
758 ASSERT(!value->IsTheHole());
759 CONVERT_ARG_CHECKED(Context, context, 1);
760 Handle<String> name(String::cast(args[2]));
761
762 // Initializations are always done in the function context.
763 context = Handle<Context>(context->fcontext());
764
765 int index;
766 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000767 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000768 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 context->Lookup(name, flags, &index, &attributes);
770
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000771 // In most situations, the property introduced by the const
772 // declaration should be present in the context extension object.
773 // However, because declaration and initialization are separate, the
774 // property might have been deleted (if it was introduced by eval)
775 // before we reach the initialization point.
776 //
777 // Example:
778 //
779 // function f() { eval("delete x; const x;"); }
780 //
781 // In that case, the initialization behaves like a normal assignment
782 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000784 // Property was found in a context.
785 if (holder->IsContext()) {
786 // The holder cannot be the function context. If it is, there
787 // should have been a const redeclaration error when declaring
788 // the const property.
789 ASSERT(!holder.is_identical_to(context));
790 if ((attributes & READ_ONLY) == 0) {
791 Handle<Context>::cast(holder)->set(index, *value);
792 }
793 } else {
794 // The holder is an arguments object.
795 ASSERT((attributes & READ_ONLY) == 0);
796 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 }
798 return *value;
799 }
800
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000801 // The property could not be found, we introduce it in the global
802 // context.
803 if (attributes == ABSENT) {
804 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
805 SetProperty(global, name, value, NONE);
806 return *value;
807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000809 // The property was present in a context extension object.
810 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000812 if (*context_ext == context->extension()) {
813 // This is the property that was introduced by the const
814 // declaration. Set it if it hasn't been set before. NOTE: We
815 // cannot use GetProperty() to get the current value as it
816 // 'unholes' the value.
817 LookupResult lookup;
818 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
819 ASSERT(lookup.IsProperty()); // the property was declared
820 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
821
822 PropertyType type = lookup.type();
823 if (type == FIELD) {
824 FixedArray* properties = context_ext->properties();
825 int index = lookup.GetFieldIndex();
826 if (properties->get(index)->IsTheHole()) {
827 properties->set(index, *value);
828 }
829 } else if (type == NORMAL) {
830 Dictionary* dictionary = context_ext->property_dictionary();
831 int entry = lookup.GetDictionaryEntry();
832 if (dictionary->ValueAt(entry)->IsTheHole()) {
833 dictionary->ValueAtPut(entry, *value);
834 }
835 } else {
836 // We should not reach here. Any real, named property should be
837 // either a field or a dictionary slot.
838 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 }
840 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000841 // The property was found in a different context extension object.
842 // Set it if it is not a read-only property.
843 if ((attributes & READ_ONLY) == 0) {
844 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
845 // Setting a property might throw an exception. Exceptions
846 // are converted to empty handles in handle operations. We
847 // need to convert back to exceptions here.
848 if (set.is_null()) {
849 ASSERT(Top::has_pending_exception());
850 return Failure::Exception();
851 }
852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 return *value;
856}
857
858
859static Object* Runtime_RegExpExec(Arguments args) {
860 HandleScope scope;
861 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000862 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
863 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 CONVERT_CHECKED(String, raw_subject, args[1]);
865 Handle<String> subject(raw_subject);
866 Handle<Object> index(args[2]);
867 ASSERT(index->IsNumber());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000868 Handle<Object> result = RegExpImpl::Exec(regexp, subject, index);
869 if (result.is_null()) return Failure::Exception();
870 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871}
872
873
874static Object* Runtime_RegExpExecGlobal(Arguments args) {
875 HandleScope scope;
876 ASSERT(args.length() == 2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000877 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
878 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879 CONVERT_CHECKED(String, raw_subject, args[1]);
880 Handle<String> subject(raw_subject);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000881 Handle<Object> result = RegExpImpl::ExecGlobal(regexp, subject);
882 if (result.is_null()) return Failure::Exception();
883 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884}
885
886
887static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
888 HandleScope scope;
889 ASSERT(args.length() == 4);
890 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
891 int index = Smi::cast(args[1])->value();
892 Handle<String> pattern = args.at<String>(2);
893 Handle<String> flags = args.at<String>(3);
894
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000895 // Get the RegExp function from the context in the literals array.
896 // This is the RegExp function from the context in which the
897 // function was created. We do not use the RegExp function from the
898 // current global context because this might be the RegExp function
899 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000900 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000901 Handle<JSFunction>(
902 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903 // Compute the regular expression literal.
904 bool has_pending_exception;
905 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000906 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
907 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000908 if (has_pending_exception) {
909 ASSERT(Top::has_pending_exception());
910 return Failure::Exception();
911 }
912 literals->set(index, *regexp);
913 return *regexp;
914}
915
916
917static Object* Runtime_FunctionGetName(Arguments args) {
918 NoHandleAllocation ha;
919 ASSERT(args.length() == 1);
920
921 CONVERT_CHECKED(JSFunction, f, args[0]);
922 return f->shared()->name();
923}
924
925
ager@chromium.org236ad962008-09-25 09:45:57 +0000926static Object* Runtime_FunctionSetName(Arguments args) {
927 NoHandleAllocation ha;
928 ASSERT(args.length() == 2);
929
930 CONVERT_CHECKED(JSFunction, f, args[0]);
931 CONVERT_CHECKED(String, name, args[1]);
932 f->shared()->set_name(name);
933 return Heap::undefined_value();
934}
935
936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937static Object* Runtime_FunctionGetScript(Arguments args) {
938 HandleScope scope;
939 ASSERT(args.length() == 1);
940
941 CONVERT_CHECKED(JSFunction, fun, args[0]);
942 Handle<Object> script = Handle<Object>(fun->shared()->script());
943 if (!script->IsScript()) return Heap::undefined_value();
944
945 return *GetScriptWrapper(Handle<Script>::cast(script));
946}
947
948
949static Object* Runtime_FunctionGetSourceCode(Arguments args) {
950 NoHandleAllocation ha;
951 ASSERT(args.length() == 1);
952
953 CONVERT_CHECKED(JSFunction, f, args[0]);
954 return f->shared()->GetSourceCode();
955}
956
957
958static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
959 NoHandleAllocation ha;
960 ASSERT(args.length() == 1);
961
962 CONVERT_CHECKED(JSFunction, fun, args[0]);
963 int pos = fun->shared()->start_position();
964 return Smi::FromInt(pos);
965}
966
967
968static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
969 NoHandleAllocation ha;
970 ASSERT(args.length() == 2);
971
972 CONVERT_CHECKED(JSFunction, fun, args[0]);
973 CONVERT_CHECKED(String, name, args[1]);
974 fun->SetInstanceClassName(name);
975 return Heap::undefined_value();
976}
977
978
979static Object* Runtime_FunctionSetLength(Arguments args) {
980 NoHandleAllocation ha;
981 ASSERT(args.length() == 2);
982
983 CONVERT_CHECKED(JSFunction, fun, args[0]);
984 CONVERT_CHECKED(Smi, length, args[1]);
985 fun->shared()->set_length(length->value());
986 return length;
987}
988
989
990static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000991 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 ASSERT(args.length() == 2);
993
994 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000995 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
996 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 return args[0]; // return TOS
998}
999
1000
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001001static Object* Runtime_FunctionIsAPIFunction(Arguments args) {
1002 NoHandleAllocation ha;
1003 ASSERT(args.length() == 1);
1004
1005 CONVERT_CHECKED(JSFunction, f, args[0]);
1006 // The function_data field of the shared function info is used exclusively by
1007 // the API.
1008 return !f->shared()->function_data()->IsUndefined() ? Heap::true_value()
1009 : Heap::false_value();
1010}
1011
1012
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013static Object* Runtime_SetCode(Arguments args) {
1014 HandleScope scope;
1015 ASSERT(args.length() == 2);
1016
1017 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
1018 Handle<JSFunction> target(raw_target);
1019 Handle<Object> code = args.at<Object>(1);
1020
1021 Handle<Context> context(target->context());
1022
1023 if (!code->IsNull()) {
1024 RUNTIME_ASSERT(code->IsJSFunction());
1025 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
1026 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
1027 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
1028 return Failure::Exception();
1029 }
1030 // Set the code, formal parameter count, and the length of the target
1031 // function.
1032 target->set_code(fun->code());
1033 target->shared()->set_length(fun->shared()->length());
1034 target->shared()->set_formal_parameter_count(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001035 fun->shared()->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001036 // Set the source code of the target function to undefined.
1037 // SetCode is only used for built-in constructors like String,
1038 // Array, and Object, and some web code
1039 // doesn't like seeing source code for constructors.
1040 target->shared()->set_script(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 context = Handle<Context>(fun->context());
1042
1043 // Make sure we get a fresh copy of the literal vector to avoid
1044 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001045 int number_of_literals = fun->NumberOfLiterals();
1046 Handle<FixedArray> literals =
1047 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001049 // Insert the object, regexp and array functions in the literals
1050 // array prefix. These are the functions that will be used when
1051 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001052 literals->set(JSFunction::kLiteralGlobalContextIndex,
1053 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001055 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 }
1057
1058 target->set_context(*context);
1059 return *target;
1060}
1061
1062
1063static Object* CharCodeAt(String* subject, Object* index) {
1064 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001065 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066 // Flatten the string. If someone wants to get a char at an index
1067 // in a cons string, it is likely that more indices will be
1068 // accessed.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001069 subject->TryFlattenIfNotFlat(StringShape(subject));
ager@chromium.org870a0b62008-11-04 11:43:05 +00001070 StringShape shape(subject);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001071 if (i >= static_cast<uint32_t>(subject->length(shape))) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001072 return Heap::nan_value();
1073 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001074 return Smi::FromInt(subject->Get(shape, i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075}
1076
1077
1078static Object* Runtime_StringCharCodeAt(Arguments args) {
1079 NoHandleAllocation ha;
1080 ASSERT(args.length() == 2);
1081
1082 CONVERT_CHECKED(String, subject, args[0]);
1083 Object* index = args[1];
1084 return CharCodeAt(subject, index);
1085}
1086
1087
1088static Object* Runtime_CharFromCode(Arguments args) {
1089 NoHandleAllocation ha;
1090 ASSERT(args.length() == 1);
1091 uint32_t code;
1092 if (Array::IndexFromObject(args[0], &code)) {
1093 if (code <= 0xffff) {
1094 return Heap::LookupSingleCharacterStringFromCode(code);
1095 }
1096 }
1097 return Heap::empty_string();
1098}
1099
1100
ager@chromium.org7c537e22008-10-16 08:43:32 +00001101// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
1102// limit, we can fix the size of tables.
1103static const int kBMMaxShift = 0xff;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001104// Reduce alphabet to this size.
1105static const int kBMAlphabetSize = 0x100;
1106// For patterns below this length, the skip length of Boyer-Moore is too short
1107// to compensate for the algorithmic overhead compared to simple brute force.
1108static const int kBMMinPatternLength = 5;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109
ager@chromium.org7c537e22008-10-16 08:43:32 +00001110// Holds the two buffers used by Boyer-Moore string search's Good Suffix
1111// shift. Only allows the last kBMMaxShift characters of the needle
1112// to be indexed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001113class BMGoodSuffixBuffers {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001114 public:
1115 BMGoodSuffixBuffers() {}
1116 inline void init(int needle_length) {
1117 ASSERT(needle_length > 1);
1118 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
1119 int len = needle_length - start;
1120 biased_suffixes_ = suffixes_ - start;
1121 biased_good_suffix_shift_ = good_suffix_shift_ - start;
1122 for (int i = 0; i <= len; i++) {
1123 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 }
1126 inline int& suffix(int index) {
1127 ASSERT(biased_suffixes_ + index >= suffixes_);
1128 return biased_suffixes_[index];
1129 }
1130 inline int& shift(int index) {
1131 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
1132 return biased_good_suffix_shift_[index];
1133 }
1134 private:
1135 int suffixes_[kBMMaxShift + 1];
1136 int good_suffix_shift_[kBMMaxShift + 1];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001137 int* biased_suffixes_;
1138 int* biased_good_suffix_shift_;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001139 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
1140};
1141
1142// buffers reused by BoyerMoore
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001143static int bad_char_occurrence[kBMAlphabetSize];
ager@chromium.org7c537e22008-10-16 08:43:32 +00001144static BMGoodSuffixBuffers bmgs_buffers;
1145
1146// Compute the bad-char table for Boyer-Moore in the static buffer.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001147template <typename pchar>
1148static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
1149 int start) {
1150 // Run forwards to populate bad_char_table, so that *last* instance
1151 // of character equivalence class is the one registered.
1152 // Notice: Doesn't include the last character.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001153 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
1154 : kBMAlphabetSize;
1155 if (start == 0) { // All patterns less than kBMMaxShift in length.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001156 memset(bad_char_occurrence, -1, table_size * sizeof(*bad_char_occurrence));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001157 } else {
1158 for (int i = 0; i < table_size; i++) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001159 bad_char_occurrence[i] = start - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001160 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001161 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001162 for (int i = start; i < pattern.length() - 1; i++) {
1163 pchar c = pattern[i];
1164 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001165 bad_char_occurrence[bucket] = i;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001166 }
1167}
1168
1169template <typename pchar>
1170static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001171 int start) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001172 int m = pattern.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001173 int len = m - start;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001174 // Compute Good Suffix tables.
1175 bmgs_buffers.init(m);
1176
1177 bmgs_buffers.shift(m-1) = 1;
1178 bmgs_buffers.suffix(m) = m + 1;
1179 pchar last_char = pattern[m - 1];
1180 int suffix = m + 1;
1181 for (int i = m; i > start;) {
1182 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
1183 if (bmgs_buffers.shift(suffix) == len) {
1184 bmgs_buffers.shift(suffix) = suffix - i;
1185 }
1186 suffix = bmgs_buffers.suffix(suffix);
1187 }
1188 i--;
1189 suffix--;
1190 bmgs_buffers.suffix(i) = suffix;
1191 if (suffix == m) {
1192 // No suffix to extend, so we check against last_char only.
1193 while (i > start && pattern[i - 1] != last_char) {
1194 if (bmgs_buffers.shift(m) == len) {
1195 bmgs_buffers.shift(m) = m - i;
1196 }
1197 i--;
1198 bmgs_buffers.suffix(i) = m;
1199 }
1200 if (i > start) {
1201 i--;
1202 suffix--;
1203 bmgs_buffers.suffix(i) = suffix;
1204 }
1205 }
1206 }
1207 if (suffix < m) {
1208 for (int i = start; i <= m; i++) {
1209 if (bmgs_buffers.shift(i) == len) {
1210 bmgs_buffers.shift(i) = suffix - start;
1211 }
1212 if (i == suffix) {
1213 suffix = bmgs_buffers.suffix(suffix);
1214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216 }
1217}
1218
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001219template <typename schar, typename pchar>
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001220static inline int CharOccurrence(int char_code) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001221 if (sizeof(schar) == 1) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001222 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001223 }
1224 if (sizeof(pchar) == 1) {
1225 if (char_code > String::kMaxAsciiCharCode) {
1226 return -1;
1227 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001228 return bad_char_occurrence[char_code];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001229 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001230 return bad_char_occurrence[char_code % kBMAlphabetSize];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001231}
1232
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001233// Restricted simplified Boyer-Moore string matching.
1234// Uses only the bad-shift table of Boyer-Moore and only uses it
1235// for the character compared to the last character of the needle.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001236template <typename schar, typename pchar>
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001237static int BoyerMooreHorsepool(Vector<const schar> subject,
1238 Vector<const pchar> pattern,
1239 int start_index,
1240 bool* complete) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001241 int n = subject.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001242 int m = pattern.length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00001243 // Only preprocess at most kBMMaxShift last characters of pattern.
1244 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245
ager@chromium.org7c537e22008-10-16 08:43:32 +00001246 BoyerMoorePopulateBadCharTable(pattern, start);
1247
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001248 int badness = -m; // How bad we are doing without a good-suffix table.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001249 int idx; // No matches found prior to this index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001250 pchar last_char = pattern[m - 1];
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001251 int last_char_shift = m - 1 - CharOccurrence<schar, pchar>(last_char);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001252 // Perform search
1253 for (idx = start_index; idx <= n - m;) {
1254 int j = m - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001255 int c;
1256 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001257 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001258 int shift = j - bc_occ;
1259 idx += shift;
1260 badness += 1 - shift; // at most zero, so badness cannot increase.
1261 if (idx > n - m) {
1262 *complete = true;
1263 return -1;
1264 }
1265 }
1266 j--;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001267 while (j >= 0 && pattern[j] == (subject[idx + j])) j--;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 if (j < 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001269 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001270 return idx;
1271 } else {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001272 idx += last_char_shift;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // Badness increases by the number of characters we have
1274 // checked, and decreases by the number of characters we
1275 // can skip by shifting. It's a measure of how we are doing
1276 // compared to reading each character exactly once.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001277 badness += (m - j) - last_char_shift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001278 if (badness > 0) {
1279 *complete = false;
1280 return idx;
1281 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001282 }
1283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001284 *complete = true;
1285 return -1;
1286}
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001288
1289template <typename schar, typename pchar>
1290static int BoyerMooreIndexOf(Vector<const schar> subject,
1291 Vector<const pchar> pattern,
1292 int idx) {
1293 int n = subject.length();
1294 int m = pattern.length();
1295 // Only preprocess at most kBMMaxShift last characters of pattern.
1296 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
1297
1298 // Build the Good Suffix table and continue searching.
1299 BoyerMoorePopulateGoodSuffixTable(pattern, start);
1300 pchar last_char = pattern[m - 1];
1301 // Continue search from i.
1302 do {
1303 int j = m - 1;
1304 schar c;
1305 while (last_char != (c = subject[idx + j])) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001306 int shift = j - CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001307 idx += shift;
1308 if (idx > n - m) {
1309 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001310 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001311 }
1312 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1313 if (j < 0) {
1314 return idx;
1315 } else if (j < start) {
1316 // we have matched more than our tables allow us to be smart about.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001317 // Fall back on BMH shift.
1318 idx += m - 1 - CharOccurrence<schar, pchar>(last_char);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001319 } else {
1320 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001321 int bc_occ = CharOccurrence<schar, pchar>(c);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001322 int shift = j - bc_occ; // Bad-char shift.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001323 if (gs_shift > shift) {
1324 shift = gs_shift;
1325 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001326 idx += shift;
1327 }
1328 } while (idx <= n - m);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001329
1330 return -1;
1331}
1332
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001333
1334template <typename schar>
ager@chromium.org7c537e22008-10-16 08:43:32 +00001335static int SingleCharIndexOf(Vector<const schar> string,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001336 schar pattern_char,
ager@chromium.org7c537e22008-10-16 08:43:32 +00001337 int start_index) {
1338 for (int i = start_index, n = string.length(); i < n; i++) {
1339 if (pattern_char == string[i]) {
1340 return i;
1341 }
1342 }
1343 return -1;
1344}
1345
1346// Trivial string search for shorter strings.
1347// On return, if "complete" is set to true, the return value is the
1348// final result of searching for the patter in the subject.
1349// If "complete" is set to false, the return value is the index where
1350// further checking should start, i.e., it's guaranteed that the pattern
1351// does not occur at a position prior to the returned index.
1352template <typename pchar, typename schar>
1353static int SimpleIndexOf(Vector<const schar> subject,
1354 Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001355 int idx,
1356 bool* complete) {
1357 // Badness is a count of how much work we have done. When we have
1358 // done enough work we decide it's probably worth switching to a better
1359 // algorithm.
1360 int badness = -10 - (pattern.length() << 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001361 // We know our pattern is at least 2 characters, we cache the first so
1362 // the common case of the first character not matching is faster.
1363 pchar pattern_first_char = pattern[0];
1364
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001365 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1366 badness++;
1367 if (badness > 0) {
1368 *complete = false;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001369 return i;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001370 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001371 if (subject[i] != pattern_first_char) continue;
1372 int j = 1;
1373 do {
1374 if (pattern[j] != subject[i+j]) {
1375 break;
1376 }
1377 j++;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001378 } while (j < pattern.length());
1379 if (j == pattern.length()) {
1380 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001381 return i;
1382 }
1383 badness += j;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001384 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001385 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001386 return -1;
1387}
1388
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001389// Simple indexOf that never bails out. For short patterns only.
1390template <typename pchar, typename schar>
1391static int SimpleIndexOf(Vector<const schar> subject,
1392 Vector<const pchar> pattern,
1393 int idx) {
1394 pchar pattern_first_char = pattern[0];
1395 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1396 if (subject[i] != pattern_first_char) continue;
1397 int j = 1;
1398 do {
1399 if (pattern[j] != subject[i+j]) {
1400 break;
1401 }
1402 j++;
1403 } while (j < pattern.length());
1404 if (j == pattern.length()) {
1405 return i;
1406 }
1407 }
1408 return -1;
1409}
1410
1411
1412// Dispatch to different algorithms.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001413template <typename schar, typename pchar>
1414static int StringMatchStrategy(Vector<const schar> sub,
1415 Vector<const pchar> pat,
1416 int start_index) {
1417 ASSERT(pat.length() > 1);
1418
1419 // We have an ASCII haystack and a non-ASCII needle. Check if there
1420 // really is a non-ASCII character in the needle and bail out if there
1421 // is.
1422 if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
1423 for (int i = 0; i < pat.length(); i++) {
1424 uc16 c = pat[i];
1425 if (c > String::kMaxAsciiCharCode) {
1426 return -1;
1427 }
1428 }
1429 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001430 if (pat.length() < kBMMinPatternLength) {
1431 // We don't believe fancy searching can ever be more efficient.
1432 // The max shift of Boyer-Moore on a pattern of this length does
1433 // not compensate for the overhead.
1434 return SimpleIndexOf(sub, pat, start_index);
1435 }
1436 // Try algorithms in order of increasing setup cost and expected performance.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001437 bool complete;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001438 int idx = SimpleIndexOf(sub, pat, start_index, &complete);
1439 if (complete) return idx;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001440 idx = BoyerMooreHorsepool(sub, pat, idx, &complete);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 if (complete) return idx;
1442 return BoyerMooreIndexOf(sub, pat, idx);
1443}
1444
1445// Perform string match of pattern on subject, starting at start index.
1446// Caller must ensure that 0 <= start_index <= sub->length(),
1447// and should check that pat->length() + start_index <= sub->length()
1448int Runtime::StringMatch(Handle<String> sub,
1449 Handle<String> pat,
1450 int start_index) {
1451 ASSERT(0 <= start_index);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001452 StringShape sub_shape(*sub);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001453 ASSERT(start_index <= sub->length(sub_shape));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001454
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001455 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001456 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457
ager@chromium.org870a0b62008-11-04 11:43:05 +00001458 int subject_length = sub->length(sub_shape);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001459 if (start_index + pattern_length > subject_length) return -1;
1460
ager@chromium.org870a0b62008-11-04 11:43:05 +00001461 if (!sub->IsFlat(sub_shape)) {
1462 FlattenString(sub);
1463 sub_shape = StringShape(*sub);
1464 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001465 StringShape pat_shape(*pat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00001467 // character patterns linear search is necessary, so any smart
1468 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001470 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
ager@chromium.org870a0b62008-11-04 11:43:05 +00001471 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001472 uc16 pchar = pat->Get(pat_shape, 0);
1473 if (pchar > String::kMaxAsciiCharCode) {
1474 return -1;
1475 }
1476 Vector<const char> ascii_vector =
1477 sub->ToAsciiVector().SubVector(start_index, subject_length);
1478 const void* pos = memchr(ascii_vector.start(),
1479 static_cast<const char>(pchar),
1480 static_cast<size_t>(ascii_vector.length()));
1481 if (pos == NULL) {
1482 return -1;
1483 }
1484 return reinterpret_cast<const char*>(pos) - ascii_vector.start()
1485 + start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00001487 return SingleCharIndexOf(sub->ToUC16Vector(),
1488 pat->Get(pat_shape, 0),
1489 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 }
1491
ager@chromium.org870a0b62008-11-04 11:43:05 +00001492 if (!pat->IsFlat(pat_shape)) {
1493 FlattenString(pat);
1494 pat_shape = StringShape(*pat);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001495 sub_shape = StringShape(*sub);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001496 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001497
ager@chromium.org7c537e22008-10-16 08:43:32 +00001498 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1499 // dispatch on type of strings
ager@chromium.org870a0b62008-11-04 11:43:05 +00001500 if (pat_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001501 Vector<const char> pat_vector = pat->ToAsciiVector();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001502 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001503 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001504 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001505 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001506 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001507 Vector<const uc16> pat_vector = pat->ToUC16Vector();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001508 if (sub_shape.IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001509 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001511 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001512}
1513
1514
1515static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001516 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001517 ASSERT(args.length() == 3);
1518
ager@chromium.org7c537e22008-10-16 08:43:32 +00001519 CONVERT_ARG_CHECKED(String, sub, 0);
1520 CONVERT_ARG_CHECKED(String, pat, 1);
1521
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001522 Object* index = args[2];
1523 uint32_t start_index;
1524 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1525
ager@chromium.org870a0b62008-11-04 11:43:05 +00001526 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001527 int position = Runtime::StringMatch(sub, pat, start_index);
1528 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529}
1530
1531
1532static Object* Runtime_StringLastIndexOf(Arguments args) {
1533 NoHandleAllocation ha;
1534 ASSERT(args.length() == 3);
1535
1536 CONVERT_CHECKED(String, sub, args[0]);
1537 CONVERT_CHECKED(String, pat, args[1]);
1538 Object* index = args[2];
1539
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001540 sub->TryFlattenIfNotFlat(StringShape(sub));
1541 pat->TryFlattenIfNotFlat(StringShape(pat));
ager@chromium.org870a0b62008-11-04 11:43:05 +00001542
1543 StringShape sub_shape(sub);
1544 StringShape pat_shape(pat);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545
1546 uint32_t start_index;
1547 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1548
ager@chromium.org870a0b62008-11-04 11:43:05 +00001549 uint32_t pattern_length = pat->length(pat_shape);
1550 uint32_t sub_length = sub->length(sub_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001552 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001554 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555
1556 for (int i = start_index; i >= 0; i--) {
1557 bool found = true;
1558 for (uint32_t j = 0; j < pattern_length; j++) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001559 if (sub->Get(sub_shape, i + j) != pat->Get(pat_shape, j)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 found = false;
1561 break;
1562 }
1563 }
1564 if (found) return Smi::FromInt(i);
1565 }
1566
1567 return Smi::FromInt(-1);
1568}
1569
1570
1571static Object* Runtime_StringLocaleCompare(Arguments args) {
1572 NoHandleAllocation ha;
1573 ASSERT(args.length() == 2);
1574
1575 CONVERT_CHECKED(String, str1, args[0]);
1576 CONVERT_CHECKED(String, str2, args[1]);
1577
1578 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.org870a0b62008-11-04 11:43:05 +00001579 StringShape shape1(str1);
1580 StringShape shape2(str2);
1581 int str1_length = str1->length(shape1);
1582 int str2_length = str2->length(shape2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583
1584 // Decide trivial cases without flattening.
1585 if (str1_length == 0) {
1586 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1587 return Smi::FromInt(-str2_length);
1588 } else {
1589 if (str2_length == 0) return Smi::FromInt(str1_length);
1590 }
1591
1592 int end = str1_length < str2_length ? str1_length : str2_length;
1593
1594 // No need to flatten if we are going to find the answer on the first
1595 // character. At this point we know there is at least one character
1596 // in each string, due to the trivial case handling above.
ager@chromium.org870a0b62008-11-04 11:43:05 +00001597 int d = str1->Get(shape1, 0) - str2->Get(shape2, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 if (d != 0) return Smi::FromInt(d);
1599
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001600 str1->TryFlattenIfNotFlat(shape1); // Shapes are no longer valid now!
1601 str2->TryFlattenIfNotFlat(shape2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602
1603 static StringInputBuffer buf1;
1604 static StringInputBuffer buf2;
1605
1606 buf1.Reset(str1);
1607 buf2.Reset(str2);
1608
1609 for (int i = 0; i < end; i++) {
1610 uint16_t char1 = buf1.GetNext();
1611 uint16_t char2 = buf2.GetNext();
1612 if (char1 != char2) return Smi::FromInt(char1 - char2);
1613 }
1614
1615 return Smi::FromInt(str1_length - str2_length);
1616}
1617
1618
1619static Object* Runtime_StringSlice(Arguments args) {
1620 NoHandleAllocation ha;
1621 ASSERT(args.length() == 3);
1622
1623 CONVERT_CHECKED(String, value, args[0]);
1624 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1625 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1626
1627 int start = FastD2I(from_number);
1628 int end = FastD2I(to_number);
1629
1630 RUNTIME_ASSERT(end >= start);
1631 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00001632 RUNTIME_ASSERT(end <= value->length());
1633 return value->Slice(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634}
1635
1636
1637static Object* Runtime_NumberToRadixString(Arguments args) {
1638 NoHandleAllocation ha;
1639 ASSERT(args.length() == 2);
1640
1641 CONVERT_DOUBLE_CHECKED(value, args[0]);
1642 if (isnan(value)) {
1643 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1644 }
1645 if (isinf(value)) {
1646 if (value < 0) {
1647 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1648 }
1649 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1650 }
1651 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1652 int radix = FastD2I(radix_number);
1653 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1654 char* str = DoubleToRadixCString(value, radix);
1655 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1656 DeleteArray(str);
1657 return result;
1658}
1659
1660
1661static Object* Runtime_NumberToFixed(Arguments args) {
1662 NoHandleAllocation ha;
1663 ASSERT(args.length() == 2);
1664
1665 CONVERT_DOUBLE_CHECKED(value, args[0]);
1666 if (isnan(value)) {
1667 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1668 }
1669 if (isinf(value)) {
1670 if (value < 0) {
1671 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1672 }
1673 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1674 }
1675 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1676 int f = FastD2I(f_number);
1677 RUNTIME_ASSERT(f >= 0);
1678 char* str = DoubleToFixedCString(value, f);
1679 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1680 DeleteArray(str);
1681 return res;
1682}
1683
1684
1685static Object* Runtime_NumberToExponential(Arguments args) {
1686 NoHandleAllocation ha;
1687 ASSERT(args.length() == 2);
1688
1689 CONVERT_DOUBLE_CHECKED(value, args[0]);
1690 if (isnan(value)) {
1691 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1692 }
1693 if (isinf(value)) {
1694 if (value < 0) {
1695 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1696 }
1697 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1698 }
1699 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1700 int f = FastD2I(f_number);
1701 RUNTIME_ASSERT(f >= -1 && f <= 20);
1702 char* str = DoubleToExponentialCString(value, f);
1703 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1704 DeleteArray(str);
1705 return res;
1706}
1707
1708
1709static Object* Runtime_NumberToPrecision(Arguments args) {
1710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 2);
1712
1713 CONVERT_DOUBLE_CHECKED(value, args[0]);
1714 if (isnan(value)) {
1715 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1716 }
1717 if (isinf(value)) {
1718 if (value < 0) {
1719 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1720 }
1721 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1722 }
1723 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1724 int f = FastD2I(f_number);
1725 RUNTIME_ASSERT(f >= 1 && f <= 21);
1726 char* str = DoubleToPrecisionCString(value, f);
1727 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1728 DeleteArray(str);
1729 return res;
1730}
1731
1732
1733// Returns a single character string where first character equals
1734// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001735static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001736 StringShape shape(*string);
1737 if (index < static_cast<uint32_t>(string->length(shape))) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001738 string->TryFlattenIfNotFlat(shape); // Invalidates shape!
ager@chromium.org870a0b62008-11-04 11:43:05 +00001739 return LookupSingleCharacterStringFromCode(
1740 string->Get(StringShape(*string), index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001742 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743}
1744
1745
1746Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1747 // Handle [] indexing on Strings
1748 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001749 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1750 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001751 }
1752
1753 // Handle [] indexing on String objects
1754 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001755 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1756 Handle<Object> result =
1757 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1758 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001759 }
1760
1761 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001762 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001763 return prototype->GetElement(index);
1764 }
1765
1766 return object->GetElement(index);
1767}
1768
1769
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001770Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1771 HandleScope scope;
1772
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001773 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001774 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 Handle<Object> error =
1776 Factory::NewTypeError("non_object_property_load",
1777 HandleVector(args, 2));
1778 return Top::Throw(*error);
1779 }
1780
1781 // Check if the given key is an array index.
1782 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001783 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 return GetElementOrCharAt(object, index);
1785 }
1786
1787 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001788 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001789 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001790 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001792 bool has_pending_exception = false;
1793 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001794 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001796 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 }
1798
ager@chromium.org32912102009-01-16 10:38:43 +00001799 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800 // the element if so.
1801 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001802 return GetElementOrCharAt(object, index);
1803 } else {
1804 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001805 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001806 }
1807}
1808
1809
1810static Object* Runtime_GetProperty(Arguments args) {
1811 NoHandleAllocation ha;
1812 ASSERT(args.length() == 2);
1813
1814 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001815 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816
1817 return Runtime::GetObjectProperty(object, key);
1818}
1819
1820
ager@chromium.org7c537e22008-10-16 08:43:32 +00001821
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001822// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001823static Object* Runtime_KeyedGetProperty(Arguments args) {
1824 NoHandleAllocation ha;
1825 ASSERT(args.length() == 2);
1826
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001827 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00001828 // itself.
1829 //
1830 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00001831 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00001832 // global proxy object never has properties. This is the case
1833 // because the global proxy object forwards everything to its hidden
1834 // prototype including local lookups.
1835 //
1836 // Additionally, we need to make sure that we do not cache results
1837 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001838 if (args[0]->IsJSObject() &&
1839 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00001840 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001841 args[1]->IsString()) {
1842 JSObject* receiver = JSObject::cast(args[0]);
1843 String* key = String::cast(args[1]);
1844 if (receiver->HasFastProperties()) {
1845 // Attempt to use lookup cache.
1846 Object* obj = Heap::GetKeyedLookupCache();
1847 if (obj->IsFailure()) return obj;
1848 LookupCache* cache = LookupCache::cast(obj);
1849 Map* receiver_map = receiver->map();
1850 int offset = cache->Lookup(receiver_map, key);
1851 if (offset != LookupCache::kNotFound) {
1852 Object* value = receiver->FastPropertyAt(offset);
1853 return value->IsTheHole() ? Heap::undefined_value() : value;
1854 }
1855 // Lookup cache miss. Perform lookup and update the cache if
1856 // appropriate.
1857 LookupResult result;
1858 receiver->LocalLookup(key, &result);
1859 if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
1860 int offset = result.GetFieldIndex();
1861 Object* obj = cache->Put(receiver_map, key, offset);
1862 if (obj->IsFailure()) return obj;
1863 Heap::SetKeyedLookupCache(LookupCache::cast(obj));
1864 Object* value = receiver->FastPropertyAt(offset);
1865 return value->IsTheHole() ? Heap::undefined_value() : value;
1866 }
1867 } else {
1868 // Attempt dictionary lookup.
1869 Dictionary* dictionary = receiver->property_dictionary();
1870 int entry = dictionary->FindStringEntry(key);
1871 if ((entry != DescriptorArray::kNotFound) &&
1872 (dictionary->DetailsAt(entry).type() == NORMAL)) {
1873 return dictionary->ValueAt(entry);
1874 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001875 }
1876 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001877
1878 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001879 return Runtime::GetObjectProperty(args.at<Object>(0),
1880 args.at<Object>(1));
1881}
1882
1883
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884Object* Runtime::SetObjectProperty(Handle<Object> object,
1885 Handle<Object> key,
1886 Handle<Object> value,
1887 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001888 HandleScope scope;
1889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001891 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 Handle<Object> error =
1893 Factory::NewTypeError("non_object_property_store",
1894 HandleVector(args, 2));
1895 return Top::Throw(*error);
1896 }
1897
1898 // If the object isn't a JavaScript object, we ignore the store.
1899 if (!object->IsJSObject()) return *value;
1900
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001901 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1902
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001903 // Check if the given key is an array index.
1904 uint32_t index;
1905 if (Array::IndexFromObject(*key, &index)) {
1906 ASSERT(attr == NONE);
1907
1908 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1909 // of a string using [] notation. We need to support this too in
1910 // JavaScript.
1911 // In the case of a String object we just need to redirect the assignment to
1912 // the underlying string if the index is in range. Since the underlying
1913 // string does nothing with the assignment then we can ignore such
1914 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001915 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001916 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001917 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001919 Handle<Object> result = SetElement(js_object, index, value);
1920 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921 return *value;
1922 }
1923
1924 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001925 Handle<Object> result;
1926 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001928 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001930 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001931 key_string->TryFlattenIfNotFlat(StringShape(*key_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001932 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001934 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935 return *value;
1936 }
1937
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 bool has_pending_exception = false;
1940 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1941 if (has_pending_exception) return Failure::Exception();
1942 Handle<String> name = Handle<String>::cast(converted);
1943
1944 if (name->AsArrayIndex(&index)) {
1945 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001946 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001948 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 }
1950}
1951
1952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953static Object* Runtime_SetProperty(Arguments args) {
1954 NoHandleAllocation ha;
1955 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1956
1957 Handle<Object> object = args.at<Object>(0);
1958 Handle<Object> key = args.at<Object>(1);
1959 Handle<Object> value = args.at<Object>(2);
1960
1961 // Compute attributes.
1962 PropertyAttributes attributes = NONE;
1963 if (args.length() == 4) {
1964 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001965 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001966 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001967 RUNTIME_ASSERT(
1968 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1969 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970 }
1971 return Runtime::SetObjectProperty(object, key, value, attributes);
1972}
1973
1974
1975// Set a local property, even if it is READ_ONLY. If the property does not
1976// exist, it will be added with attributes NONE.
1977static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1978 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001979 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001980 CONVERT_CHECKED(JSObject, object, args[0]);
1981 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001982 // Compute attributes.
1983 PropertyAttributes attributes = NONE;
1984 if (args.length() == 4) {
1985 CONVERT_CHECKED(Smi, value_obj, args[3]);
1986 int unchecked_value = value_obj->value();
1987 // Only attribute bits should be set.
1988 RUNTIME_ASSERT(
1989 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1990 attributes = static_cast<PropertyAttributes>(unchecked_value);
1991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001992
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001993 return object->
1994 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995}
1996
1997
1998static Object* Runtime_DeleteProperty(Arguments args) {
1999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 2);
2001
2002 CONVERT_CHECKED(JSObject, object, args[0]);
2003 CONVERT_CHECKED(String, key, args[1]);
2004 return object->DeleteProperty(key);
2005}
2006
2007
2008static Object* Runtime_HasLocalProperty(Arguments args) {
2009 NoHandleAllocation ha;
2010 ASSERT(args.length() == 2);
2011 CONVERT_CHECKED(String, key, args[1]);
2012
2013 // Only JS objects can have properties.
2014 if (args[0]->IsJSObject()) {
2015 JSObject* object = JSObject::cast(args[0]);
2016 if (object->HasLocalProperty(key)) return Heap::true_value();
2017 } else if (args[0]->IsString()) {
2018 // Well, there is one exception: Handle [] on strings.
2019 uint32_t index;
2020 if (key->AsArrayIndex(&index)) {
2021 String* string = String::cast(args[0]);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002022 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023 return Heap::true_value();
2024 }
2025 }
2026 return Heap::false_value();
2027}
2028
2029
2030static Object* Runtime_HasProperty(Arguments args) {
2031 NoHandleAllocation na;
2032 ASSERT(args.length() == 2);
2033
2034 // Only JS objects can have properties.
2035 if (args[0]->IsJSObject()) {
2036 JSObject* object = JSObject::cast(args[0]);
2037 CONVERT_CHECKED(String, key, args[1]);
2038 if (object->HasProperty(key)) return Heap::true_value();
2039 }
2040 return Heap::false_value();
2041}
2042
2043
2044static Object* Runtime_HasElement(Arguments args) {
2045 NoHandleAllocation na;
2046 ASSERT(args.length() == 2);
2047
2048 // Only JS objects can have elements.
2049 if (args[0]->IsJSObject()) {
2050 JSObject* object = JSObject::cast(args[0]);
2051 CONVERT_CHECKED(Smi, index_obj, args[1]);
2052 uint32_t index = index_obj->value();
2053 if (object->HasElement(index)) return Heap::true_value();
2054 }
2055 return Heap::false_value();
2056}
2057
2058
2059static Object* Runtime_IsPropertyEnumerable(Arguments args) {
2060 NoHandleAllocation ha;
2061 ASSERT(args.length() == 2);
2062
2063 CONVERT_CHECKED(JSObject, object, args[0]);
2064 CONVERT_CHECKED(String, key, args[1]);
2065
2066 uint32_t index;
2067 if (key->AsArrayIndex(&index)) {
2068 return Heap::ToBoolean(object->HasElement(index));
2069 }
2070
ager@chromium.org870a0b62008-11-04 11:43:05 +00002071 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
2072 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073}
2074
2075
2076static Object* Runtime_GetPropertyNames(Arguments args) {
2077 HandleScope scope;
2078 ASSERT(args.length() == 1);
2079
2080 CONVERT_CHECKED(JSObject, raw_object, args[0]);
2081 Handle<JSObject> object(raw_object);
2082 return *GetKeysFor(object);
2083}
2084
2085
2086// Returns either a FixedArray as Runtime_GetPropertyNames,
2087// or, if the given object has an enum cache that contains
2088// all enumerable properties of the object and its prototypes
2089// have none, the map of the object. This is used to speed up
2090// the check for deletions during a for-in.
2091static Object* Runtime_GetPropertyNamesFast(Arguments args) {
2092 ASSERT(args.length() == 1);
2093
2094 CONVERT_CHECKED(JSObject, raw_object, args[0]);
2095
2096 if (raw_object->IsSimpleEnum()) return raw_object->map();
2097
2098 HandleScope scope;
2099 Handle<JSObject> object(raw_object);
2100 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
2101
2102 // Test again, since cache may have been built by preceding call.
2103 if (object->IsSimpleEnum()) return object->map();
2104
2105 return *content;
2106}
2107
2108
2109static Object* Runtime_GetArgumentsProperty(Arguments args) {
2110 NoHandleAllocation ha;
2111 ASSERT(args.length() == 1);
2112
2113 // Compute the frame holding the arguments.
2114 JavaScriptFrameIterator it;
2115 it.AdvanceToArgumentsFrame();
2116 JavaScriptFrame* frame = it.frame();
2117
2118 // Get the actual number of provided arguments.
2119 const uint32_t n = frame->GetProvidedParametersCount();
2120
2121 // Try to convert the key to an index. If successful and within
2122 // index return the the argument from the frame.
2123 uint32_t index;
2124 if (Array::IndexFromObject(args[0], &index) && index < n) {
2125 return frame->GetParameter(index);
2126 }
2127
2128 // Convert the key to a string.
2129 HandleScope scope;
2130 bool exception = false;
2131 Handle<Object> converted =
2132 Execution::ToString(args.at<Object>(0), &exception);
2133 if (exception) return Failure::Exception();
2134 Handle<String> key = Handle<String>::cast(converted);
2135
2136 // Try to convert the string key into an array index.
2137 if (key->AsArrayIndex(&index)) {
2138 if (index < n) {
2139 return frame->GetParameter(index);
2140 } else {
2141 return Top::initial_object_prototype()->GetElement(index);
2142 }
2143 }
2144
2145 // Handle special arguments properties.
2146 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
2147 if (key->Equals(Heap::callee_symbol())) return frame->function();
2148
2149 // Lookup in the initial Object.prototype object.
2150 return Top::initial_object_prototype()->GetProperty(*key);
2151}
2152
2153
2154static Object* Runtime_ToBool(Arguments args) {
2155 NoHandleAllocation ha;
2156 ASSERT(args.length() == 1);
2157
2158 return args[0]->ToBoolean();
2159}
2160
2161
2162// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
2163// Possible optimizations: put the type string into the oddballs.
2164static Object* Runtime_Typeof(Arguments args) {
2165 NoHandleAllocation ha;
2166
2167 Object* obj = args[0];
2168 if (obj->IsNumber()) return Heap::number_symbol();
2169 HeapObject* heap_obj = HeapObject::cast(obj);
2170
2171 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002172 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173
2174 InstanceType instance_type = heap_obj->map()->instance_type();
2175 if (instance_type < FIRST_NONSTRING_TYPE) {
2176 return Heap::string_symbol();
2177 }
2178
2179 switch (instance_type) {
2180 case ODDBALL_TYPE:
2181 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
2182 return Heap::boolean_symbol();
2183 }
2184 if (heap_obj->IsNull()) {
2185 return Heap::object_symbol();
2186 }
2187 ASSERT(heap_obj->IsUndefined());
2188 return Heap::undefined_symbol();
2189 case JS_FUNCTION_TYPE:
2190 return Heap::function_symbol();
2191 default:
2192 // For any kind of object not handled above, the spec rule for
2193 // host objects gives that it is okay to return "object"
2194 return Heap::object_symbol();
2195 }
2196}
2197
2198
2199static Object* Runtime_StringToNumber(Arguments args) {
2200 NoHandleAllocation ha;
2201 ASSERT(args.length() == 1);
2202 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002203 subject->TryFlattenIfNotFlat(StringShape(subject));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002204 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
2205}
2206
2207
2208static Object* Runtime_StringFromCharCodeArray(Arguments args) {
2209 NoHandleAllocation ha;
2210 ASSERT(args.length() == 1);
2211
2212 CONVERT_CHECKED(JSArray, codes, args[0]);
2213 int length = Smi::cast(codes->length())->value();
2214
2215 // Check if the string can be ASCII.
2216 int i;
2217 for (i = 0; i < length; i++) {
2218 Object* element = codes->GetElement(i);
2219 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2220 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
2221 break;
2222 }
2223
2224 Object* object = NULL;
2225 if (i == length) { // The string is ASCII.
2226 object = Heap::AllocateRawAsciiString(length);
2227 } else { // The string is not ASCII.
2228 object = Heap::AllocateRawTwoByteString(length);
2229 }
2230
2231 if (object->IsFailure()) return object;
2232 String* result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002233 StringShape result_shape(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234 for (int i = 0; i < length; i++) {
2235 Object* element = codes->GetElement(i);
2236 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002237 result->Set(result_shape, i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002238 }
2239 return result;
2240}
2241
2242
2243// kNotEscaped is generated by the following:
2244//
2245// #!/bin/perl
2246// for (my $i = 0; $i < 256; $i++) {
2247// print "\n" if $i % 16 == 0;
2248// my $c = chr($i);
2249// my $escaped = 1;
2250// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
2251// print $escaped ? "0, " : "1, ";
2252// }
2253
2254
2255static bool IsNotEscaped(uint16_t character) {
2256 // Only for 8 bit characters, the rest are always escaped (in a different way)
2257 ASSERT(character < 256);
2258 static const char kNotEscaped[256] = {
2259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2261 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
2262 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2263 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2264 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
2265 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2266 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
2267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2275 };
2276 return kNotEscaped[character] != 0;
2277}
2278
2279
2280static Object* Runtime_URIEscape(Arguments args) {
2281 const char hex_chars[] = "0123456789ABCDEF";
2282 NoHandleAllocation ha;
2283 ASSERT(args.length() == 1);
2284 CONVERT_CHECKED(String, source, args[0]);
2285
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002286 source->TryFlattenIfNotFlat(StringShape(source));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002287
2288 int escaped_length = 0;
2289 int length = source->length();
2290 {
2291 Access<StringInputBuffer> buffer(&string_input_buffer);
2292 buffer->Reset(source);
2293 while (buffer->has_more()) {
2294 uint16_t character = buffer->GetNext();
2295 if (character >= 256) {
2296 escaped_length += 6;
2297 } else if (IsNotEscaped(character)) {
2298 escaped_length++;
2299 } else {
2300 escaped_length += 3;
2301 }
2302 // We don't allow strings that are longer than Smi range.
2303 if (!Smi::IsValid(escaped_length)) {
2304 Top::context()->mark_out_of_memory();
2305 return Failure::OutOfMemoryException();
2306 }
2307 }
2308 }
2309 // No length change implies no change. Return original string if no change.
2310 if (escaped_length == length) {
2311 return source;
2312 }
2313 Object* o = Heap::AllocateRawAsciiString(escaped_length);
2314 if (o->IsFailure()) return o;
2315 String* destination = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002316 StringShape dshape(destination);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002317 int dest_position = 0;
2318
2319 Access<StringInputBuffer> buffer(&string_input_buffer);
2320 buffer->Rewind();
2321 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002322 uint16_t chr = buffer->GetNext();
2323 if (chr >= 256) {
2324 destination->Set(dshape, dest_position, '%');
2325 destination->Set(dshape, dest_position+1, 'u');
2326 destination->Set(dshape, dest_position+2, hex_chars[chr >> 12]);
2327 destination->Set(dshape, dest_position+3, hex_chars[(chr >> 8) & 0xf]);
2328 destination->Set(dshape, dest_position+4, hex_chars[(chr >> 4) & 0xf]);
2329 destination->Set(dshape, dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002330 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002331 } else if (IsNotEscaped(chr)) {
2332 destination->Set(dshape, dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002333 dest_position++;
2334 } else {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002335 destination->Set(dshape, dest_position, '%');
2336 destination->Set(dshape, dest_position+1, hex_chars[chr >> 4]);
2337 destination->Set(dshape, dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002338 dest_position += 3;
2339 }
2340 }
2341 return destination;
2342}
2343
2344
2345static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
2346 static const signed char kHexValue['g'] = {
2347 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2348 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2349 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2350 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
2351 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2352 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2353 -1, 10, 11, 12, 13, 14, 15 };
2354
2355 if (character1 > 'f') return -1;
2356 int hi = kHexValue[character1];
2357 if (hi == -1) return -1;
2358 if (character2 > 'f') return -1;
2359 int lo = kHexValue[character2];
2360 if (lo == -1) return -1;
2361 return (hi << 4) + lo;
2362}
2363
2364
ager@chromium.org870a0b62008-11-04 11:43:05 +00002365static inline int Unescape(String* source,
2366 StringShape shape,
2367 int i,
2368 int length,
2369 int* step) {
2370 uint16_t character = source->Get(shape, i);
2371 int32_t hi = 0;
2372 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002373 if (character == '%' &&
2374 i <= length - 6 &&
ager@chromium.org870a0b62008-11-04 11:43:05 +00002375 source->Get(shape, i + 1) == 'u' &&
2376 (hi = TwoDigitHex(source->Get(shape, i + 2),
2377 source->Get(shape, i + 3))) != -1 &&
2378 (lo = TwoDigitHex(source->Get(shape, i + 4),
2379 source->Get(shape, i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002380 *step = 6;
2381 return (hi << 8) + lo;
2382 } else if (character == '%' &&
2383 i <= length - 3 &&
ager@chromium.org870a0b62008-11-04 11:43:05 +00002384 (lo = TwoDigitHex(source->Get(shape, i + 1),
2385 source->Get(shape, i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002386 *step = 3;
2387 return lo;
2388 } else {
2389 *step = 1;
2390 return character;
2391 }
2392}
2393
2394
2395static Object* Runtime_URIUnescape(Arguments args) {
2396 NoHandleAllocation ha;
2397 ASSERT(args.length() == 1);
2398 CONVERT_CHECKED(String, source, args[0]);
2399
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002400 source->TryFlattenIfNotFlat(StringShape(source));
ager@chromium.org870a0b62008-11-04 11:43:05 +00002401 StringShape source_shape(source);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002402
2403 bool ascii = true;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002404 int length = source->length(source_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002405
2406 int unescaped_length = 0;
2407 for (int i = 0; i < length; unescaped_length++) {
2408 int step;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002409 if (Unescape(source,
2410 source_shape,
2411 i,
2412 length,
2413 &step) >
2414 String::kMaxAsciiCharCode)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002415 ascii = false;
2416 i += step;
2417 }
2418
2419 // No length change implies no change. Return original string if no change.
2420 if (unescaped_length == length)
2421 return source;
2422
2423 Object* o = ascii ?
2424 Heap::AllocateRawAsciiString(unescaped_length) :
2425 Heap::AllocateRawTwoByteString(unescaped_length);
2426 if (o->IsFailure()) return o;
2427 String* destination = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002428 StringShape destination_shape(destination);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002429
2430 int dest_position = 0;
2431 for (int i = 0; i < length; dest_position++) {
2432 int step;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002433 destination->Set(destination_shape,
2434 dest_position,
2435 Unescape(source, source_shape, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002436 i += step;
2437 }
2438 return destination;
2439}
2440
2441
2442static Object* Runtime_StringParseInt(Arguments args) {
2443 NoHandleAllocation ha;
2444
2445 CONVERT_CHECKED(String, s, args[0]);
2446 CONVERT_DOUBLE_CHECKED(n, args[1]);
2447 int radix = FastD2I(n);
2448
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002449 s->TryFlattenIfNotFlat(StringShape(s));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002450
ager@chromium.org870a0b62008-11-04 11:43:05 +00002451 StringShape shape(s);
2452
2453 int len = s->length(shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002454 int i;
2455
2456 // Skip leading white space.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002457 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(shape, i)); i++) ;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002458 if (i == len) return Heap::nan_value();
2459
2460 // Compute the sign (default to +).
2461 int sign = 1;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002462 if (s->Get(shape, i) == '-') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002463 sign = -1;
2464 i++;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002465 } else if (s->Get(shape, i) == '+') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002466 i++;
2467 }
2468
2469 // Compute the radix if 0.
2470 if (radix == 0) {
2471 radix = 10;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002472 if (i < len && s->Get(shape, i) == '0') {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002473 radix = 8;
2474 if (i + 1 < len) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002475 int c = s->Get(shape, i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002476 if (c == 'x' || c == 'X') {
2477 radix = 16;
2478 i += 2;
2479 }
2480 }
2481 }
2482 } else if (radix == 16) {
2483 // Allow 0x or 0X prefix if radix is 16.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002484 if (i + 1 < len && s->Get(shape, i) == '0') {
2485 int c = s->Get(shape, i + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002486 if (c == 'x' || c == 'X') i += 2;
2487 }
2488 }
2489
2490 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2491 double value;
2492 int end_index = StringToInt(s, i, radix, &value);
2493 if (end_index != i) {
2494 return Heap::NumberFromDouble(sign * value);
2495 }
2496 return Heap::nan_value();
2497}
2498
2499
2500static Object* Runtime_StringParseFloat(Arguments args) {
2501 NoHandleAllocation ha;
2502 CONVERT_CHECKED(String, str, args[0]);
2503
2504 // ECMA-262 section 15.1.2.3, empty string is NaN
2505 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
2506
2507 // Create a number object from the value.
2508 return Heap::NumberFromDouble(value);
2509}
2510
2511
2512static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
2513static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
2514
2515
2516template <class Converter>
2517static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002518 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002519 NoHandleAllocation ha;
2520
2521 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002522 s->TryFlattenIfNotFlat(StringShape(s));
ager@chromium.org870a0b62008-11-04 11:43:05 +00002523 StringShape shape(s);
2524
2525 int raw_string_length = s->length(shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002526 // Assume that the string is not empty; we need this assumption later
2527 if (raw_string_length == 0) return s;
2528 int length = raw_string_length;
2529
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002530
2531 // We try this twice, once with the assumption that the result is
2532 // no longer than the input and, if that assumption breaks, again
2533 // with the exact length. This is implemented using a goto back
2534 // to this label if we discover that the assumption doesn't hold.
2535 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00002536 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002537 try_convert:
2538
2539 // Allocate the resulting string.
2540 //
2541 // NOTE: This assumes that the upper/lower case of an ascii
2542 // character is also ascii. This is currently the case, but it
2543 // might break in the future if we implement more context and locale
2544 // dependent upper/lower conversions.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002545 Object* o = shape.IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002546 ? Heap::AllocateRawAsciiString(length)
2547 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002548 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002549 String* result = String::cast(o);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002550 StringShape result_shape(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002551 bool has_changed_character = false;
2552
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002553 // Convert all characters to upper case, assuming that they will fit
2554 // in the buffer
2555 Access<StringInputBuffer> buffer(&string_input_buffer);
2556 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002557 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002558 int i = 0;
2559 // We can assume that the string is not empty
2560 uc32 current = buffer->GetNext();
2561 while (i < length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002562 bool has_next = buffer->has_more();
2563 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002564 int char_length = mapping->get(current, next, chars);
2565 if (char_length == 0) {
2566 // The case conversion of this character is the character itself.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002567 result->Set(result_shape, i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568 i++;
2569 } else if (char_length == 1) {
2570 // Common case: converting the letter resulted in one character.
2571 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002572 result->Set(result_shape, i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002573 has_changed_character = true;
2574 i++;
2575 } else if (length == raw_string_length) {
2576 // We've assumed that the result would be as long as the
2577 // input but here is a character that converts to several
2578 // characters. No matter, we calculate the exact length
2579 // of the result and try the whole thing again.
2580 //
2581 // Note that this leaves room for optimization. We could just
2582 // memcpy what we already have to the result string. Also,
2583 // the result string is the last object allocated we could
2584 // "realloc" it and probably, in the vast majority of cases,
2585 // extend the existing string to be able to hold the full
2586 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002587 int next_length = 0;
2588 if (has_next) {
2589 next_length = mapping->get(next, 0, chars);
2590 if (next_length == 0) next_length = 1;
2591 }
2592 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002593 while (buffer->has_more()) {
2594 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002595 // NOTE: we use 0 as the next character here because, while
2596 // the next character may affect what a character converts to,
2597 // it does not in any case affect the length of what it convert
2598 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599 int char_length = mapping->get(current, 0, chars);
2600 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002601 current_length += char_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002602 }
2603 length = current_length;
2604 goto try_convert;
2605 } else {
2606 for (int j = 0; j < char_length; j++) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002607 result->Set(result_shape, i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 i++;
2609 }
2610 has_changed_character = true;
2611 }
2612 current = next;
2613 }
2614 if (has_changed_character) {
2615 return result;
2616 } else {
2617 // If we didn't actually change anything in doing the conversion
2618 // we simple return the result and let the converted string
2619 // become garbage; there is no reason to keep two identical strings
2620 // alive.
2621 return s;
2622 }
2623}
2624
2625
2626static Object* Runtime_StringToLowerCase(Arguments args) {
2627 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2628}
2629
2630
2631static Object* Runtime_StringToUpperCase(Arguments args) {
2632 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2633}
2634
2635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002636static Object* Runtime_NumberToString(Arguments args) {
2637 NoHandleAllocation ha;
2638 ASSERT(args.length() == 1);
2639
2640 Object* number = args[0];
2641 RUNTIME_ASSERT(number->IsNumber());
2642
2643 Object* cached = Heap::GetNumberStringCache(number);
2644 if (cached != Heap::undefined_value()) {
2645 return cached;
2646 }
2647
2648 char arr[100];
2649 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2650 const char* str;
2651 if (number->IsSmi()) {
2652 int num = Smi::cast(number)->value();
2653 str = IntToCString(num, buffer);
2654 } else {
2655 double num = HeapNumber::cast(number)->value();
2656 str = DoubleToCString(num, buffer);
2657 }
2658 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2659
2660 if (!result->IsFailure()) {
2661 Heap::SetNumberStringCache(number, String::cast(result));
2662 }
2663 return result;
2664}
2665
2666
2667static Object* Runtime_NumberToInteger(Arguments args) {
2668 NoHandleAllocation ha;
2669 ASSERT(args.length() == 1);
2670
2671 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002672 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673 CONVERT_DOUBLE_CHECKED(number, obj);
2674 return Heap::NumberFromDouble(DoubleToInteger(number));
2675}
2676
2677
2678static Object* Runtime_NumberToJSUint32(Arguments args) {
2679 NoHandleAllocation ha;
2680 ASSERT(args.length() == 1);
2681
2682 Object* obj = args[0];
2683 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2684 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2685 return Heap::NumberFromUint32(number);
2686}
2687
2688
2689static Object* Runtime_NumberToJSInt32(Arguments args) {
2690 NoHandleAllocation ha;
2691 ASSERT(args.length() == 1);
2692
2693 Object* obj = args[0];
2694 if (obj->IsSmi()) return obj;
2695 CONVERT_DOUBLE_CHECKED(number, obj);
2696 return Heap::NumberFromInt32(DoubleToInt32(number));
2697}
2698
2699
ager@chromium.org870a0b62008-11-04 11:43:05 +00002700// Converts a Number to a Smi, if possible. Returns NaN if the number is not
2701// a small integer.
2702static Object* Runtime_NumberToSmi(Arguments args) {
2703 NoHandleAllocation ha;
2704 ASSERT(args.length() == 1);
2705
2706 Object* obj = args[0];
2707 if (obj->IsSmi()) {
2708 return obj;
2709 }
2710 if (obj->IsHeapNumber()) {
2711 double value = HeapNumber::cast(obj)->value();
2712 int int_value = FastD2I(value);
2713 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
2714 return Smi::FromInt(int_value);
2715 }
2716 }
2717 return Heap::nan_value();
2718}
2719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720static Object* Runtime_NumberAdd(Arguments args) {
2721 NoHandleAllocation ha;
2722 ASSERT(args.length() == 2);
2723
2724 CONVERT_DOUBLE_CHECKED(x, args[0]);
2725 CONVERT_DOUBLE_CHECKED(y, args[1]);
2726 return Heap::AllocateHeapNumber(x + y);
2727}
2728
2729
2730static Object* Runtime_NumberSub(Arguments args) {
2731 NoHandleAllocation ha;
2732 ASSERT(args.length() == 2);
2733
2734 CONVERT_DOUBLE_CHECKED(x, args[0]);
2735 CONVERT_DOUBLE_CHECKED(y, args[1]);
2736 return Heap::AllocateHeapNumber(x - y);
2737}
2738
2739
2740static Object* Runtime_NumberMul(Arguments args) {
2741 NoHandleAllocation ha;
2742 ASSERT(args.length() == 2);
2743
2744 CONVERT_DOUBLE_CHECKED(x, args[0]);
2745 CONVERT_DOUBLE_CHECKED(y, args[1]);
2746 return Heap::AllocateHeapNumber(x * y);
2747}
2748
2749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750static Object* Runtime_NumberUnaryMinus(Arguments args) {
2751 NoHandleAllocation ha;
2752 ASSERT(args.length() == 1);
2753
2754 CONVERT_DOUBLE_CHECKED(x, args[0]);
2755 return Heap::AllocateHeapNumber(-x);
2756}
2757
2758
2759static Object* Runtime_NumberDiv(Arguments args) {
2760 NoHandleAllocation ha;
2761 ASSERT(args.length() == 2);
2762
2763 CONVERT_DOUBLE_CHECKED(x, args[0]);
2764 CONVERT_DOUBLE_CHECKED(y, args[1]);
2765 return Heap::NewNumberFromDouble(x / y);
2766}
2767
2768
2769static Object* Runtime_NumberMod(Arguments args) {
2770 NoHandleAllocation ha;
2771 ASSERT(args.length() == 2);
2772
2773 CONVERT_DOUBLE_CHECKED(x, args[0]);
2774 CONVERT_DOUBLE_CHECKED(y, args[1]);
2775
2776#ifdef WIN32
2777 // Workaround MS fmod bugs. ECMA-262 says:
2778 // dividend is finite and divisor is an infinity => result equals dividend
2779 // dividend is a zero and divisor is nonzero finite => result equals dividend
2780 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2781 !(x == 0 && (y != 0 && isfinite(y))))
2782#endif
2783 x = fmod(x, y);
2784 // NewNumberFromDouble may return a Smi instead of a Number object
2785 return Heap::NewNumberFromDouble(x);
2786}
2787
2788
2789static Object* Runtime_StringAdd(Arguments args) {
2790 NoHandleAllocation ha;
2791 ASSERT(args.length() == 2);
2792
2793 CONVERT_CHECKED(String, str1, args[0]);
2794 CONVERT_CHECKED(String, str2, args[1]);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002795 int len1 = str1->length();
2796 int len2 = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002797 if (len1 == 0) return str2;
2798 if (len2 == 0) return str1;
2799 int length_sum = len1 + len2;
2800 // Make sure that an out of memory exception is thrown if the length
2801 // of the new cons string is too large to fit in a Smi.
2802 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2803 Top::context()->mark_out_of_memory();
2804 return Failure::OutOfMemoryException();
2805 }
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002806 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807}
2808
2809
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002810template<typename sinkchar>
2811static inline void StringBuilderConcatHelper(String* special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002812 StringShape special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002813 sinkchar* sink,
2814 FixedArray* fixed_array,
2815 int array_length) {
2816 int position = 0;
2817 for (int i = 0; i < array_length; i++) {
2818 Object* element = fixed_array->get(i);
2819 if (element->IsSmi()) {
2820 int len = Smi::cast(element)->value();
2821 int pos = len >> 11;
2822 len &= 0x7ff;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002823 String::WriteToFlat(special,
2824 special_shape,
2825 sink + position,
2826 pos,
2827 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002828 position += len;
2829 } else {
2830 String* string = String::cast(element);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002831 StringShape shape(string);
2832 int element_length = string->length(shape);
2833 String::WriteToFlat(string, shape, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002834 position += element_length;
2835 }
2836 }
2837}
2838
2839
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840static Object* Runtime_StringBuilderConcat(Arguments args) {
2841 NoHandleAllocation ha;
2842 ASSERT(args.length() == 2);
2843 CONVERT_CHECKED(JSArray, array, args[0]);
2844 CONVERT_CHECKED(String, special, args[1]);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002845 StringShape special_shape(special);
2846 int special_length = special->length(special_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847 Object* smi_array_length = array->length();
2848 if (!smi_array_length->IsSmi()) {
2849 Top::context()->mark_out_of_memory();
2850 return Failure::OutOfMemoryException();
2851 }
2852 int array_length = Smi::cast(smi_array_length)->value();
2853 if (!array->HasFastElements()) {
2854 return Top::Throw(Heap::illegal_argument_symbol());
2855 }
2856 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002857 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002858 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002859 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002860
2861 if (array_length == 0) {
2862 return Heap::empty_string();
2863 } else if (array_length == 1) {
2864 Object* first = fixed_array->get(0);
2865 if (first->IsString()) return first;
2866 }
2867
ager@chromium.org870a0b62008-11-04 11:43:05 +00002868 bool ascii = special_shape.IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002869 int position = 0;
2870 for (int i = 0; i < array_length; i++) {
2871 Object* elt = fixed_array->get(i);
2872 if (elt->IsSmi()) {
2873 int len = Smi::cast(elt)->value();
2874 int pos = len >> 11;
2875 len &= 0x7ff;
2876 if (pos + len > special_length) {
2877 return Top::Throw(Heap::illegal_argument_symbol());
2878 }
2879 position += len;
2880 } else if (elt->IsString()) {
2881 String* element = String::cast(elt);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002882 StringShape element_shape(element);
2883 int element_length = element->length(element_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002884 if (!Smi::IsValid(element_length + position)) {
2885 Top::context()->mark_out_of_memory();
2886 return Failure::OutOfMemoryException();
2887 }
2888 position += element_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002889 if (ascii && !element_shape.IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892 } else {
2893 return Top::Throw(Heap::illegal_argument_symbol());
2894 }
2895 }
2896
2897 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002899
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900 if (ascii) {
2901 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002902 if (object->IsFailure()) return object;
2903 SeqAsciiString* answer = SeqAsciiString::cast(object);
2904 StringBuilderConcatHelper(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002905 special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002906 answer->GetChars(),
2907 fixed_array,
2908 array_length);
2909 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910 } else {
2911 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002912 if (object->IsFailure()) return object;
2913 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
2914 StringBuilderConcatHelper(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00002915 special_shape,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002916 answer->GetChars(),
2917 fixed_array,
2918 array_length);
2919 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002921}
2922
2923
2924static Object* Runtime_NumberOr(Arguments args) {
2925 NoHandleAllocation ha;
2926 ASSERT(args.length() == 2);
2927
2928 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2929 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2930 return Heap::NumberFromInt32(x | y);
2931}
2932
2933
2934static Object* Runtime_NumberAnd(Arguments args) {
2935 NoHandleAllocation ha;
2936 ASSERT(args.length() == 2);
2937
2938 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2939 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2940 return Heap::NumberFromInt32(x & y);
2941}
2942
2943
2944static Object* Runtime_NumberXor(Arguments args) {
2945 NoHandleAllocation ha;
2946 ASSERT(args.length() == 2);
2947
2948 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2949 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2950 return Heap::NumberFromInt32(x ^ y);
2951}
2952
2953
2954static Object* Runtime_NumberNot(Arguments args) {
2955 NoHandleAllocation ha;
2956 ASSERT(args.length() == 1);
2957
2958 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2959 return Heap::NumberFromInt32(~x);
2960}
2961
2962
2963static Object* Runtime_NumberShl(Arguments args) {
2964 NoHandleAllocation ha;
2965 ASSERT(args.length() == 2);
2966
2967 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2968 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2969 return Heap::NumberFromInt32(x << (y & 0x1f));
2970}
2971
2972
2973static Object* Runtime_NumberShr(Arguments args) {
2974 NoHandleAllocation ha;
2975 ASSERT(args.length() == 2);
2976
2977 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2978 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2979 return Heap::NumberFromUint32(x >> (y & 0x1f));
2980}
2981
2982
2983static Object* Runtime_NumberSar(Arguments args) {
2984 NoHandleAllocation ha;
2985 ASSERT(args.length() == 2);
2986
2987 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2988 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2989 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2990}
2991
2992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002993static Object* Runtime_NumberEquals(Arguments args) {
2994 NoHandleAllocation ha;
2995 ASSERT(args.length() == 2);
2996
2997 CONVERT_DOUBLE_CHECKED(x, args[0]);
2998 CONVERT_DOUBLE_CHECKED(y, args[1]);
2999 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
3000 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
3001 if (x == y) return Smi::FromInt(EQUAL);
3002 Object* result;
3003 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
3004 result = Smi::FromInt(EQUAL);
3005 } else {
3006 result = Smi::FromInt(NOT_EQUAL);
3007 }
3008 return result;
3009}
3010
3011
3012static Object* Runtime_StringEquals(Arguments args) {
3013 NoHandleAllocation ha;
3014 ASSERT(args.length() == 2);
3015
3016 CONVERT_CHECKED(String, x, args[0]);
3017 CONVERT_CHECKED(String, y, args[1]);
3018
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003019 bool not_equal = !x->Equals(y);
3020 // This is slightly convoluted because the value that signifies
3021 // equality is 0 and inequality is 1 so we have to negate the result
3022 // from String::Equals.
3023 ASSERT(not_equal == 0 || not_equal == 1);
3024 STATIC_CHECK(EQUAL == 0);
3025 STATIC_CHECK(NOT_EQUAL == 1);
3026 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003027}
3028
3029
3030static Object* Runtime_NumberCompare(Arguments args) {
3031 NoHandleAllocation ha;
3032 ASSERT(args.length() == 3);
3033
3034 CONVERT_DOUBLE_CHECKED(x, args[0]);
3035 CONVERT_DOUBLE_CHECKED(y, args[1]);
3036 if (isnan(x) || isnan(y)) return args[2];
3037 if (x == y) return Smi::FromInt(EQUAL);
3038 if (isless(x, y)) return Smi::FromInt(LESS);
3039 return Smi::FromInt(GREATER);
3040}
3041
3042
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003043// Compare two Smis as if they were converted to strings and then
3044// compared lexicographically.
3045static Object* Runtime_SmiLexicographicCompare(Arguments args) {
3046 NoHandleAllocation ha;
3047 ASSERT(args.length() == 2);
3048
3049 // Arrays for the individual characters of the two Smis. Smis are
3050 // 31 bit integers and 10 decimal digits are therefore enough.
3051 static int x_elms[10];
3052 static int y_elms[10];
3053
3054 // Extract the integer values from the Smis.
3055 CONVERT_CHECKED(Smi, x, args[0]);
3056 CONVERT_CHECKED(Smi, y, args[1]);
3057 int x_value = x->value();
3058 int y_value = y->value();
3059
3060 // If the integers are equal so are the string representations.
3061 if (x_value == y_value) return Smi::FromInt(EQUAL);
3062
3063 // If one of the integers are zero the normal integer order is the
3064 // same as the lexicographic order of the string representations.
3065 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
3066
ager@chromium.org32912102009-01-16 10:38:43 +00003067 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003068 // smallest because the char code of '-' is less than the char code
3069 // of any digit. Otherwise, we make both values positive.
3070 if (x_value < 0 || y_value < 0) {
3071 if (y_value >= 0) return Smi::FromInt(LESS);
3072 if (x_value >= 0) return Smi::FromInt(GREATER);
3073 x_value = -x_value;
3074 y_value = -y_value;
3075 }
3076
3077 // Convert the integers to arrays of their decimal digits.
3078 int x_index = 0;
3079 int y_index = 0;
3080 while (x_value > 0) {
3081 x_elms[x_index++] = x_value % 10;
3082 x_value /= 10;
3083 }
3084 while (y_value > 0) {
3085 y_elms[y_index++] = y_value % 10;
3086 y_value /= 10;
3087 }
3088
3089 // Loop through the arrays of decimal digits finding the first place
3090 // where they differ.
3091 while (--x_index >= 0 && --y_index >= 0) {
3092 int diff = x_elms[x_index] - y_elms[y_index];
3093 if (diff != 0) return Smi::FromInt(diff);
3094 }
3095
3096 // If one array is a suffix of the other array, the longest array is
3097 // the representation of the largest of the Smis in the
3098 // lexicographic ordering.
3099 return Smi::FromInt(x_index - y_index);
3100}
3101
3102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103static Object* Runtime_StringCompare(Arguments args) {
3104 NoHandleAllocation ha;
3105 ASSERT(args.length() == 2);
3106
3107 CONVERT_CHECKED(String, x, args[0]);
3108 CONVERT_CHECKED(String, y, args[1]);
3109
ager@chromium.org870a0b62008-11-04 11:43:05 +00003110 StringShape x_shape(x);
3111 StringShape y_shape(y);
3112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003113 // A few fast case tests before we flatten.
3114 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003115 if (y->length(y_shape) == 0) {
3116 if (x->length(x_shape) == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003117 return Smi::FromInt(GREATER);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003118 } else if (x->length(x_shape) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003119 return Smi::FromInt(LESS);
3120 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003121
ager@chromium.org870a0b62008-11-04 11:43:05 +00003122 int d = x->Get(x_shape, 0) - y->Get(y_shape, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003123 if (d < 0) return Smi::FromInt(LESS);
3124 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003126 x->TryFlattenIfNotFlat(x_shape); // Shapes are no longer valid!
3127 y->TryFlattenIfNotFlat(y_shape);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003128
3129 static StringInputBuffer bufx;
3130 static StringInputBuffer bufy;
3131 bufx.Reset(x);
3132 bufy.Reset(y);
3133 while (bufx.has_more() && bufy.has_more()) {
3134 int d = bufx.GetNext() - bufy.GetNext();
3135 if (d < 0) return Smi::FromInt(LESS);
3136 else if (d > 0) return Smi::FromInt(GREATER);
3137 }
3138
3139 // x is (non-trivial) prefix of y:
3140 if (bufy.has_more()) return Smi::FromInt(LESS);
3141 // y is prefix of x:
3142 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
3143}
3144
3145
3146static Object* Runtime_Math_abs(Arguments args) {
3147 NoHandleAllocation ha;
3148 ASSERT(args.length() == 1);
3149
3150 CONVERT_DOUBLE_CHECKED(x, args[0]);
3151 return Heap::AllocateHeapNumber(fabs(x));
3152}
3153
3154
3155static Object* Runtime_Math_acos(Arguments args) {
3156 NoHandleAllocation ha;
3157 ASSERT(args.length() == 1);
3158
3159 CONVERT_DOUBLE_CHECKED(x, args[0]);
3160 return Heap::AllocateHeapNumber(acos(x));
3161}
3162
3163
3164static Object* Runtime_Math_asin(Arguments args) {
3165 NoHandleAllocation ha;
3166 ASSERT(args.length() == 1);
3167
3168 CONVERT_DOUBLE_CHECKED(x, args[0]);
3169 return Heap::AllocateHeapNumber(asin(x));
3170}
3171
3172
3173static Object* Runtime_Math_atan(Arguments args) {
3174 NoHandleAllocation ha;
3175 ASSERT(args.length() == 1);
3176
3177 CONVERT_DOUBLE_CHECKED(x, args[0]);
3178 return Heap::AllocateHeapNumber(atan(x));
3179}
3180
3181
3182static Object* Runtime_Math_atan2(Arguments args) {
3183 NoHandleAllocation ha;
3184 ASSERT(args.length() == 2);
3185
3186 CONVERT_DOUBLE_CHECKED(x, args[0]);
3187 CONVERT_DOUBLE_CHECKED(y, args[1]);
3188 double result;
3189 if (isinf(x) && isinf(y)) {
3190 // Make sure that the result in case of two infinite arguments
3191 // is a multiple of Pi / 4. The sign of the result is determined
3192 // by the first argument (x) and the sign of the second argument
3193 // determines the multiplier: one or three.
3194 static double kPiDividedBy4 = 0.78539816339744830962;
3195 int multiplier = (x < 0) ? -1 : 1;
3196 if (y < 0) multiplier *= 3;
3197 result = multiplier * kPiDividedBy4;
3198 } else {
3199 result = atan2(x, y);
3200 }
3201 return Heap::AllocateHeapNumber(result);
3202}
3203
3204
3205static Object* Runtime_Math_ceil(Arguments args) {
3206 NoHandleAllocation ha;
3207 ASSERT(args.length() == 1);
3208
3209 CONVERT_DOUBLE_CHECKED(x, args[0]);
3210 return Heap::NumberFromDouble(ceiling(x));
3211}
3212
3213
3214static Object* Runtime_Math_cos(Arguments args) {
3215 NoHandleAllocation ha;
3216 ASSERT(args.length() == 1);
3217
3218 CONVERT_DOUBLE_CHECKED(x, args[0]);
3219 return Heap::AllocateHeapNumber(cos(x));
3220}
3221
3222
3223static Object* Runtime_Math_exp(Arguments args) {
3224 NoHandleAllocation ha;
3225 ASSERT(args.length() == 1);
3226
3227 CONVERT_DOUBLE_CHECKED(x, args[0]);
3228 return Heap::AllocateHeapNumber(exp(x));
3229}
3230
3231
3232static Object* Runtime_Math_floor(Arguments args) {
3233 NoHandleAllocation ha;
3234 ASSERT(args.length() == 1);
3235
3236 CONVERT_DOUBLE_CHECKED(x, args[0]);
3237 return Heap::NumberFromDouble(floor(x));
3238}
3239
3240
3241static Object* Runtime_Math_log(Arguments args) {
3242 NoHandleAllocation ha;
3243 ASSERT(args.length() == 1);
3244
3245 CONVERT_DOUBLE_CHECKED(x, args[0]);
3246 return Heap::AllocateHeapNumber(log(x));
3247}
3248
3249
3250static Object* Runtime_Math_pow(Arguments args) {
3251 NoHandleAllocation ha;
3252 ASSERT(args.length() == 2);
3253
3254 CONVERT_DOUBLE_CHECKED(x, args[0]);
3255 CONVERT_DOUBLE_CHECKED(y, args[1]);
3256 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
3257 return Heap::nan_value();
3258 } else if (y == 0) {
3259 return Smi::FromInt(1);
3260 } else {
3261 return Heap::AllocateHeapNumber(pow(x, y));
3262 }
3263}
3264
3265// Returns a number value with positive sign, greater than or equal to
3266// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00003267static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003269 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003270
3271 // To get much better precision, we combine the results of two
3272 // invocations of random(). The result is computed by normalizing a
3273 // double in the range [0, RAND_MAX + 1) obtained by adding the
3274 // high-order bits in the range [0, RAND_MAX] with the low-order
3275 // bits in the range [0, 1).
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003276 double lo = static_cast<double>(random()) * (1.0 / (RAND_MAX + 1.0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003277 double hi = static_cast<double>(random());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003278 double result = (hi + lo) * (1.0 / (RAND_MAX + 1.0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003279 ASSERT(result >= 0 && result < 1);
3280 return Heap::AllocateHeapNumber(result);
3281}
3282
3283
3284static Object* Runtime_Math_round(Arguments args) {
3285 NoHandleAllocation ha;
3286 ASSERT(args.length() == 1);
3287
3288 CONVERT_DOUBLE_CHECKED(x, args[0]);
3289 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
3290 return Heap::NumberFromDouble(floor(x + 0.5));
3291}
3292
3293
3294static Object* Runtime_Math_sin(Arguments args) {
3295 NoHandleAllocation ha;
3296 ASSERT(args.length() == 1);
3297
3298 CONVERT_DOUBLE_CHECKED(x, args[0]);
3299 return Heap::AllocateHeapNumber(sin(x));
3300}
3301
3302
3303static Object* Runtime_Math_sqrt(Arguments args) {
3304 NoHandleAllocation ha;
3305 ASSERT(args.length() == 1);
3306
3307 CONVERT_DOUBLE_CHECKED(x, args[0]);
3308 return Heap::AllocateHeapNumber(sqrt(x));
3309}
3310
3311
3312static Object* Runtime_Math_tan(Arguments args) {
3313 NoHandleAllocation ha;
3314 ASSERT(args.length() == 1);
3315
3316 CONVERT_DOUBLE_CHECKED(x, args[0]);
3317 return Heap::AllocateHeapNumber(tan(x));
3318}
3319
3320
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003321// The NewArguments function is only used when constructing the
3322// arguments array when calling non-functions from JavaScript in
3323// runtime.js:CALL_NON_FUNCTION.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003324static Object* Runtime_NewArguments(Arguments args) {
3325 NoHandleAllocation ha;
3326 ASSERT(args.length() == 1);
3327
3328 // ECMA-262, 3rd., 10.1.8, p.39
3329 CONVERT_CHECKED(JSFunction, callee, args[0]);
3330
3331 // Compute the frame holding the arguments.
3332 JavaScriptFrameIterator it;
3333 it.AdvanceToArgumentsFrame();
3334 JavaScriptFrame* frame = it.frame();
3335
3336 const int length = frame->GetProvidedParametersCount();
3337 Object* result = Heap::AllocateArgumentsObject(callee, length);
3338 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003339 if (length > 0) {
3340 Object* obj = Heap::AllocateFixedArray(length);
3341 if (obj->IsFailure()) return obj;
3342 FixedArray* array = FixedArray::cast(obj);
3343 ASSERT(array->length() == length);
3344 WriteBarrierMode mode = array->GetWriteBarrierMode();
3345 for (int i = 0; i < length; i++) {
3346 array->set(i, frame->GetParameter(i), mode);
3347 }
3348 JSObject::cast(result)->set_elements(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003349 }
3350 return result;
3351}
3352
3353
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003354static Object* Runtime_NewArgumentsFast(Arguments args) {
3355 NoHandleAllocation ha;
3356 ASSERT(args.length() == 3);
3357
3358 JSFunction* callee = JSFunction::cast(args[0]);
3359 Object** parameters = reinterpret_cast<Object**>(args[1]);
3360 const int length = Smi::cast(args[2])->value();
3361
3362 Object* result = Heap::AllocateArgumentsObject(callee, length);
3363 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003364 ASSERT(Heap::InNewSpace(result));
3365
3366 // Allocate the elements if needed.
3367 if (length > 0) {
3368 // Allocate the fixed array.
3369 Object* obj = Heap::AllocateRawFixedArray(length);
3370 if (obj->IsFailure()) return obj;
3371 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
3372 FixedArray* array = FixedArray::cast(obj);
3373 array->set_length(length);
3374 WriteBarrierMode mode = array->GetWriteBarrierMode();
3375 for (int i = 0; i < length; i++) {
3376 array->set(i, *--parameters, mode);
3377 }
3378 JSObject::cast(result)->set_elements(FixedArray::cast(obj),
3379 SKIP_WRITE_BARRIER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003380 }
3381 return result;
3382}
3383
3384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003385static Object* Runtime_NewClosure(Arguments args) {
3386 HandleScope scope;
3387 ASSERT(args.length() == 2);
3388 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
3389 CONVERT_ARG_CHECKED(Context, context, 1);
3390
3391 Handle<JSFunction> result =
3392 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3393 return *result;
3394}
3395
3396
3397static Object* Runtime_NewObject(Arguments args) {
3398 NoHandleAllocation ha;
3399 ASSERT(args.length() == 1);
3400
3401 Object* constructor = args[0];
3402 if (constructor->IsJSFunction()) {
3403 JSFunction* function = JSFunction::cast(constructor);
3404
ager@chromium.org32912102009-01-16 10:38:43 +00003405 // Handle stepping into constructors if step into is active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 if (Debug::StepInActive()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003407 HandleScope scope;
3408 Debug::HandleStepIn(Handle<JSFunction>(function), 0, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 }
3410
3411 if (function->has_initial_map() &&
3412 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
3413 // The 'Function' function ignores the receiver object when
3414 // called using 'new' and creates a new JSFunction object that
3415 // is returned. The receiver object is only used for error
3416 // reporting if an error occurs when constructing the new
3417 // JSFunction. AllocateJSObject should not be used to allocate
3418 // JSFunctions since it does not properly initialize the shared
3419 // part of the function. Since the receiver is ignored anyway,
3420 // we use the global object as the receiver instead of a new
3421 // JSFunction object. This way, errors are reported the same
3422 // way whether or not 'Function' is called using 'new'.
3423 return Top::context()->global();
3424 }
3425 return Heap::AllocateJSObject(function);
3426 }
3427
3428 HandleScope scope;
3429 Handle<Object> cons(constructor);
3430 // The constructor is not a function; throw a type error.
3431 Handle<Object> type_error =
3432 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
3433 return Top::Throw(*type_error);
3434}
3435
3436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003437static Object* Runtime_LazyCompile(Arguments args) {
3438 HandleScope scope;
3439 ASSERT(args.length() == 1);
3440
3441 Handle<JSFunction> function = args.at<JSFunction>(0);
3442#ifdef DEBUG
3443 if (FLAG_trace_lazy) {
3444 PrintF("[lazy: ");
3445 function->shared()->name()->Print();
3446 PrintF("]\n");
3447 }
3448#endif
3449
3450 // Compile the target function.
3451 ASSERT(!function->is_compiled());
3452 if (!CompileLazy(function, KEEP_EXCEPTION)) {
3453 return Failure::Exception();
3454 }
3455
3456 return function->code();
3457}
3458
3459
3460static Object* Runtime_GetCalledFunction(Arguments args) {
3461 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00003462 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463 StackFrameIterator it;
3464 // Get past the JS-to-C exit frame.
3465 ASSERT(it.frame()->is_exit());
3466 it.Advance();
3467 // Get past the CALL_NON_FUNCTION activation frame.
3468 ASSERT(it.frame()->is_java_script());
3469 it.Advance();
3470 // Argument adaptor frames do not copy the function; we have to skip
3471 // past them to get to the real calling frame.
3472 if (it.frame()->is_arguments_adaptor()) it.Advance();
3473 // Get the function from the top of the expression stack of the
3474 // calling frame.
3475 StandardFrame* frame = StandardFrame::cast(it.frame());
3476 int index = frame->ComputeExpressionsCount() - 1;
3477 Object* result = frame->GetExpression(index);
3478 return result;
3479}
3480
3481
3482static Object* Runtime_GetFunctionDelegate(Arguments args) {
3483 HandleScope scope;
3484 ASSERT(args.length() == 1);
3485 RUNTIME_ASSERT(!args[0]->IsJSFunction());
3486 return *Execution::GetFunctionDelegate(args.at<Object>(0));
3487}
3488
3489
3490static Object* Runtime_NewContext(Arguments args) {
3491 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003492 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493
kasper.lund7276f142008-07-30 08:49:36 +00003494 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
3496 Object* result = Heap::AllocateFunctionContext(length, function);
3497 if (result->IsFailure()) return result;
3498
3499 Top::set_context(Context::cast(result));
3500
kasper.lund7276f142008-07-30 08:49:36 +00003501 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003502}
3503
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003504static Object* PushContextHelper(Object* object, bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003506 Object* js_object = object;
3507 if (!js_object->IsJSObject()) {
3508 js_object = js_object->ToObject();
3509 if (js_object->IsFailure()) {
3510 if (!Failure::cast(js_object)->IsInternalError()) return js_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003512 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 Handle<Object> result =
3514 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
3515 return Top::Throw(*result);
3516 }
3517 }
3518
3519 Object* result =
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003520 Heap::AllocateWithContext(Top::context(),
3521 JSObject::cast(js_object),
3522 is_catch_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523 if (result->IsFailure()) return result;
3524
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003525 Context* context = Context::cast(result);
3526 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003527
kasper.lund7276f142008-07-30 08:49:36 +00003528 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529}
3530
3531
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003532static Object* Runtime_PushContext(Arguments args) {
3533 NoHandleAllocation ha;
3534 ASSERT(args.length() == 1);
3535 return PushContextHelper(args[0], false);
3536}
3537
3538
3539static Object* Runtime_PushCatchContext(Arguments args) {
3540 NoHandleAllocation ha;
3541 ASSERT(args.length() == 1);
3542 return PushContextHelper(args[0], true);
3543}
3544
3545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546static Object* Runtime_LookupContext(Arguments args) {
3547 HandleScope scope;
3548 ASSERT(args.length() == 2);
3549
3550 CONVERT_ARG_CHECKED(Context, context, 0);
3551 CONVERT_ARG_CHECKED(String, name, 1);
3552
3553 int index;
3554 PropertyAttributes attributes;
3555 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003556 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003557 context->Lookup(name, flags, &index, &attributes);
3558
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003559 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003560 ASSERT(holder->IsJSObject());
3561 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 }
3563
3564 // No intermediate context found. Use global object by default.
3565 return Top::context()->global();
3566}
3567
3568
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569// A mechanism to return pairs of Object*'s. This is somewhat
3570// compiler-dependent as it assumes that a 64-bit value (a long long)
3571// is returned via two registers (edx:eax on ia32). Both the ia32 and
3572// arm platform support this; it is mostly an issue of "coaxing" the
3573// compiler to do the right thing.
3574//
3575// TODO(1236026): This is a non-portable hack that should be removed.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003576typedef uint64_t ObjectPair;
3577static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003579 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580}
3581
3582
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003583static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3585 USE(attributes);
3586 return x->IsTheHole() ? Heap::undefined_value() : x;
3587}
3588
3589
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003590static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
3591 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003592 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003593 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003594 JSFunction* context_extension_function =
3595 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003596 // If the holder isn't a context extension object, we just return it
3597 // as the receiver. This allows arguments objects to be used as
3598 // receivers, but only if they are put in the context scope chain
3599 // explicitly via a with-statement.
3600 Object* constructor = holder->map()->constructor();
3601 if (constructor != context_extension_function) return holder;
3602 // Fall back to using the global object as the receiver if the
3603 // property turns out to be a local variable allocated in a context
3604 // extension object - introduced via eval.
3605 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003606}
3607
3608
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003609static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 HandleScope scope;
3611 ASSERT(args.length() == 2);
3612
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003613 if (!args[0]->IsContext() || !args[1]->IsString()) {
3614 return MakePair(IllegalOperation(), NULL);
3615 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003617 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618
3619 int index;
3620 PropertyAttributes attributes;
3621 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003622 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623 context->Lookup(name, flags, &index, &attributes);
3624
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003625 // If the index is non-negative, the slot has been found in a local
3626 // variable or a parameter. Read it from the context object or the
3627 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003629 // If the "property" we were looking for is a local variable or an
3630 // argument in a context, the receiver is the global object; see
3631 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
3632 JSObject* receiver = Top::context()->global()->global_receiver();
3633 Object* value = (holder->IsContext())
3634 ? Context::cast(*holder)->get(index)
3635 : JSObject::cast(*holder)->GetElement(index);
3636 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 }
3638
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003639 // If the holder is found, we read the property from it.
3640 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003641 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003642 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003643 JSObject* receiver;
3644 if (object->IsGlobalObject()) {
3645 receiver = GlobalObject::cast(object)->global_receiver();
3646 } else if (context->is_exception_holder(*holder)) {
3647 receiver = Top::context()->global()->global_receiver();
3648 } else {
3649 receiver = ComputeReceiverForNonGlobal(object);
3650 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003651 // No need to unhole the value here. This is taken care of by the
3652 // GetProperty function.
3653 Object* value = object->GetProperty(*name);
3654 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655 }
3656
3657 if (throw_error) {
3658 // The property doesn't exist - throw exception.
3659 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003660 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 return MakePair(Top::Throw(*reference_error), NULL);
3662 } else {
3663 // The property doesn't exist - return undefined
3664 return MakePair(Heap::undefined_value(), Heap::undefined_value());
3665 }
3666}
3667
3668
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003669static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 return LoadContextSlotHelper(args, true);
3671}
3672
3673
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003674static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 return LoadContextSlotHelper(args, false);
3676}
3677
3678
3679static Object* Runtime_StoreContextSlot(Arguments args) {
3680 HandleScope scope;
3681 ASSERT(args.length() == 3);
3682
3683 Handle<Object> value(args[0]);
3684 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003685 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003686
3687 int index;
3688 PropertyAttributes attributes;
3689 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003690 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691 context->Lookup(name, flags, &index, &attributes);
3692
3693 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003694 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 // Ignore if read_only variable.
3696 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003697 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 }
3699 } else {
3700 ASSERT((attributes & READ_ONLY) == 0);
3701 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003702 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 USE(result);
3704 ASSERT(!result->IsFailure());
3705 }
3706 return *value;
3707 }
3708
3709 // Slow case: The property is not in a FixedArray context.
3710 // It is either in an JSObject extension context or it was not found.
3711 Handle<JSObject> context_ext;
3712
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003713 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003714 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003715 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 } else {
3717 // The property was not found. It needs to be stored in the global context.
3718 ASSERT(attributes == ABSENT);
3719 attributes = NONE;
3720 context_ext = Handle<JSObject>(Top::context()->global());
3721 }
3722
3723 // Set the property, but ignore if read_only variable.
3724 if ((attributes & READ_ONLY) == 0) {
3725 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3726 if (set.is_null()) {
3727 // Failure::Exception is converted to a null handle in the
3728 // handle-based methods such as SetProperty. We therefore need
3729 // to convert null handles back to exceptions.
3730 ASSERT(Top::has_pending_exception());
3731 return Failure::Exception();
3732 }
3733 }
3734 return *value;
3735}
3736
3737
3738static Object* Runtime_Throw(Arguments args) {
3739 HandleScope scope;
3740 ASSERT(args.length() == 1);
3741
3742 return Top::Throw(args[0]);
3743}
3744
3745
3746static Object* Runtime_ReThrow(Arguments args) {
3747 HandleScope scope;
3748 ASSERT(args.length() == 1);
3749
3750 return Top::ReThrow(args[0]);
3751}
3752
3753
3754static Object* Runtime_ThrowReferenceError(Arguments args) {
3755 HandleScope scope;
3756 ASSERT(args.length() == 1);
3757
3758 Handle<Object> name(args[0]);
3759 Handle<Object> reference_error =
3760 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3761 return Top::Throw(*reference_error);
3762}
3763
3764
3765static Object* Runtime_StackOverflow(Arguments args) {
3766 NoHandleAllocation na;
3767 return Top::StackOverflow();
3768}
3769
3770
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003771static Object* Runtime_DebugBreak(Arguments args) {
3772 ASSERT(args.length() == 0);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003773 return Execution::DebugBreakHelper();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774}
3775
3776
3777static Object* Runtime_StackGuard(Arguments args) {
3778 ASSERT(args.length() == 1);
3779
3780 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003781 if (StackGuard::IsStackOverflow()) {
3782 return Runtime_StackOverflow(args);
3783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003785 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786}
3787
3788
3789// NOTE: These PrintXXX functions are defined for all builds (not just
3790// DEBUG builds) because we may want to be able to trace function
3791// calls in all modes.
3792static void PrintString(String* str) {
3793 // not uncommon to have empty strings
3794 if (str->length() > 0) {
3795 SmartPointer<char> s =
3796 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3797 PrintF("%s", *s);
3798 }
3799}
3800
3801
3802static void PrintObject(Object* obj) {
3803 if (obj->IsSmi()) {
3804 PrintF("%d", Smi::cast(obj)->value());
3805 } else if (obj->IsString() || obj->IsSymbol()) {
3806 PrintString(String::cast(obj));
3807 } else if (obj->IsNumber()) {
3808 PrintF("%g", obj->Number());
3809 } else if (obj->IsFailure()) {
3810 PrintF("<failure>");
3811 } else if (obj->IsUndefined()) {
3812 PrintF("<undefined>");
3813 } else if (obj->IsNull()) {
3814 PrintF("<null>");
3815 } else if (obj->IsTrue()) {
3816 PrintF("<true>");
3817 } else if (obj->IsFalse()) {
3818 PrintF("<false>");
3819 } else {
3820 PrintF("%p", obj);
3821 }
3822}
3823
3824
3825static int StackSize() {
3826 int n = 0;
3827 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3828 return n;
3829}
3830
3831
3832static void PrintTransition(Object* result) {
3833 // indentation
3834 { const int nmax = 80;
3835 int n = StackSize();
3836 if (n <= nmax)
3837 PrintF("%4d:%*s", n, n, "");
3838 else
3839 PrintF("%4d:%*s", n, nmax, "...");
3840 }
3841
3842 if (result == NULL) {
3843 // constructor calls
3844 JavaScriptFrameIterator it;
3845 JavaScriptFrame* frame = it.frame();
3846 if (frame->IsConstructor()) PrintF("new ");
3847 // function name
3848 Object* fun = frame->function();
3849 if (fun->IsJSFunction()) {
3850 PrintObject(JSFunction::cast(fun)->shared()->name());
3851 } else {
3852 PrintObject(fun);
3853 }
3854 // function arguments
3855 // (we are intentionally only printing the actually
3856 // supplied parameters, not all parameters required)
3857 PrintF("(this=");
3858 PrintObject(frame->receiver());
3859 const int length = frame->GetProvidedParametersCount();
3860 for (int i = 0; i < length; i++) {
3861 PrintF(", ");
3862 PrintObject(frame->GetParameter(i));
3863 }
3864 PrintF(") {\n");
3865
3866 } else {
3867 // function result
3868 PrintF("} -> ");
3869 PrintObject(result);
3870 PrintF("\n");
3871 }
3872}
3873
3874
3875static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003876 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003877 NoHandleAllocation ha;
3878 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003879 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003880}
3881
3882
3883static Object* Runtime_TraceExit(Arguments args) {
3884 NoHandleAllocation ha;
3885 PrintTransition(args[0]);
3886 return args[0]; // return TOS
3887}
3888
3889
3890static Object* Runtime_DebugPrint(Arguments args) {
3891 NoHandleAllocation ha;
3892 ASSERT(args.length() == 1);
3893
3894#ifdef DEBUG
3895 if (args[0]->IsString()) {
3896 // If we have a string, assume it's a code "marker"
3897 // and print some interesting cpu debugging info.
3898 JavaScriptFrameIterator it;
3899 JavaScriptFrame* frame = it.frame();
3900 PrintF("fp = %p, sp = %p, pp = %p: ",
3901 frame->fp(), frame->sp(), frame->pp());
3902 } else {
3903 PrintF("DebugPrint: ");
3904 }
3905 args[0]->Print();
3906#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003907 // ShortPrint is available in release mode. Print is not.
3908 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909#endif
3910 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003911 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912
3913 return args[0]; // return TOS
3914}
3915
3916
3917static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003918 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919 NoHandleAllocation ha;
3920 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003921 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003922}
3923
3924
mads.s.ager31e71382008-08-13 09:32:07 +00003925static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003926 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003927 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928
3929 // According to ECMA-262, section 15.9.1, page 117, the precision of
3930 // the number in a Date object representing a particular instant in
3931 // time is milliseconds. Therefore, we floor the result of getting
3932 // the OS time.
3933 double millis = floor(OS::TimeCurrentMillis());
3934 return Heap::NumberFromDouble(millis);
3935}
3936
3937
3938static Object* Runtime_DateParseString(Arguments args) {
3939 HandleScope scope;
3940 ASSERT(args.length() == 1);
3941
3942 CONVERT_CHECKED(String, string_object, args[0]);
3943
3944 Handle<String> str(string_object);
3945 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3946 if (DateParser::Parse(*str, *output)) {
3947 return *Factory::NewJSArrayWithElements(output);
3948 } else {
3949 return *Factory::null_value();
3950 }
3951}
3952
3953
3954static Object* Runtime_DateLocalTimezone(Arguments args) {
3955 NoHandleAllocation ha;
3956 ASSERT(args.length() == 1);
3957
3958 CONVERT_DOUBLE_CHECKED(x, args[0]);
3959 char* zone = OS::LocalTimezone(x);
3960 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3961}
3962
3963
3964static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3965 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003966 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967
3968 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3969}
3970
3971
3972static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3973 NoHandleAllocation ha;
3974 ASSERT(args.length() == 1);
3975
3976 CONVERT_DOUBLE_CHECKED(x, args[0]);
3977 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3978}
3979
3980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003981static Object* Runtime_NumberIsFinite(Arguments args) {
3982 NoHandleAllocation ha;
3983 ASSERT(args.length() == 1);
3984
3985 CONVERT_DOUBLE_CHECKED(value, args[0]);
3986 Object* result;
3987 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3988 result = Heap::false_value();
3989 } else {
3990 result = Heap::true_value();
3991 }
3992 return result;
3993}
3994
3995
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003996static Object* Runtime_GlobalReceiver(Arguments args) {
3997 ASSERT(args.length() == 1);
3998 Object* global = args[0];
3999 if (!global->IsJSGlobalObject()) return Heap::null_value();
4000 return JSGlobalObject::cast(global)->global_receiver();
4001}
4002
4003
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004static Object* Runtime_CompileString(Arguments args) {
4005 HandleScope scope;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004006 ASSERT(args.length() == 2);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004007 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00004008 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004009
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004010 // Compile source string.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004011 Handle<JSFunction> boilerplate =
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004012 Compiler::CompileEval(source, line_offset->value(), true);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004013 if (boilerplate.is_null()) return Failure::Exception();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004014 Handle<Context> context(Top::context()->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 Handle<JSFunction> fun =
4016 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4017 return *fun;
4018}
4019
4020
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004021static Handle<JSFunction> GetBuiltinFunction(String* name) {
4022 LookupResult result;
4023 Top::global_context()->builtins()->LocalLookup(name, &result);
4024 return Handle<JSFunction>(JSFunction::cast(result.GetValue()));
4025}
4026
4027
4028static Object* CompileDirectEval(Handle<String> source) {
4029 // Compute the eval context.
4030 HandleScope scope;
4031 StackFrameLocator locator;
4032 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
4033 Handle<Context> context(Context::cast(frame->context()));
4034 bool is_global = context->IsGlobalContext();
4035
4036 // Compile source string.
4037 Handle<JSFunction> boilerplate = Compiler::CompileEval(source, 0, is_global);
4038 if (boilerplate.is_null()) return Failure::Exception();
4039 Handle<JSFunction> fun =
4040 Factory::NewFunctionFromBoilerplate(boilerplate, context);
4041 return *fun;
4042}
4043
4044
4045static Object* Runtime_ResolvePossiblyDirectEval(Arguments args) {
4046 ASSERT(args.length() == 2);
4047
4048 HandleScope scope;
4049
4050 CONVERT_ARG_CHECKED(JSFunction, callee, 0);
4051
4052 Handle<Object> receiver;
4053
4054 // Find where the 'eval' symbol is bound. It is unaliased only if
4055 // it is bound in the global context.
4056 StackFrameLocator locator;
4057 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
4058 Handle<Context> context(Context::cast(frame->context()));
4059 int index;
4060 PropertyAttributes attributes;
4061 while (!context.is_null()) {
4062 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
4063 &index, &attributes);
4064 if (attributes != ABSENT) break;
4065 if (context->is_function_context()) {
4066 context = Handle<Context>(Context::cast(context->closure()->context()));
4067 } else {
4068 context = Handle<Context>(context->previous());
4069 }
4070 }
4071
4072 if (context->IsGlobalContext()) {
4073 // 'eval' is bound in the global context, but it may have been overwritten.
4074 // Compare it to the builtin 'GlobalEval' function to make sure.
4075 Handle<JSFunction> global_eval =
4076 GetBuiltinFunction(Heap::global_eval_symbol());
4077 if (global_eval.is_identical_to(callee)) {
4078 // A direct eval call.
4079 if (args[1]->IsString()) {
4080 CONVERT_ARG_CHECKED(String, source, 1);
4081 // A normal eval call on a string. Compile it and return the
4082 // compiled function bound in the local context.
4083 Object* compiled_source = CompileDirectEval(source);
4084 if (compiled_source->IsFailure()) return compiled_source;
4085 receiver = Handle<Object>(frame->receiver());
4086 callee = Handle<JSFunction>(JSFunction::cast(compiled_source));
4087 } else {
4088 // An eval call that is not called on a string. Global eval
4089 // deals better with this.
4090 receiver = Handle<Object>(Top::global_context()->global());
4091 }
4092 } else {
4093 // 'eval' is overwritten. Just call the function with the given arguments.
4094 receiver = Handle<Object>(Top::global_context()->global());
4095 }
4096 } else {
4097 // 'eval' is not bound in the global context. Just call the function
4098 // with the given arguments. This is not necessarily the global eval.
4099 if (receiver->IsContext()) {
4100 context = Handle<Context>::cast(receiver);
4101 receiver = Handle<Object>(context->get(index));
4102 }
4103 }
4104
4105 Handle<FixedArray> call = Factory::NewFixedArray(2);
4106 call->set(0, *callee);
4107 call->set(1, *receiver);
4108 return *call;
4109}
4110
4111
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112static Object* Runtime_CompileScript(Arguments args) {
4113 HandleScope scope;
4114 ASSERT(args.length() == 4);
4115
4116 CONVERT_ARG_CHECKED(String, source, 0);
4117 CONVERT_ARG_CHECKED(String, script, 1);
4118 CONVERT_CHECKED(Smi, line_attrs, args[2]);
4119 int line = line_attrs->value();
4120 CONVERT_CHECKED(Smi, col_attrs, args[3]);
4121 int col = col_attrs->value();
4122 Handle<JSFunction> boilerplate =
4123 Compiler::Compile(source, script, line, col, NULL, NULL);
4124 if (boilerplate.is_null()) return Failure::Exception();
4125 Handle<JSFunction> fun =
4126 Factory::NewFunctionFromBoilerplate(boilerplate,
4127 Handle<Context>(Top::context()));
4128 return *fun;
4129}
4130
4131
4132static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
4133 // This utility adjusts the property attributes for newly created Function
4134 // object ("new Function(...)") by changing the map.
4135 // All it does is changing the prototype property to enumerable
4136 // as specified in ECMA262, 15.3.5.2.
4137 HandleScope scope;
4138 ASSERT(args.length() == 1);
4139 CONVERT_ARG_CHECKED(JSFunction, func, 0);
4140 ASSERT(func->map()->instance_type() ==
4141 Top::function_instance_map()->instance_type());
4142 ASSERT(func->map()->instance_size() ==
4143 Top::function_instance_map()->instance_size());
4144 func->set_map(*Top::function_instance_map());
4145 return *func;
4146}
4147
4148
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004149// Push an array unto an array of arrays if it is not already in the
4150// array. Returns true if the element was pushed on the stack and
4151// false otherwise.
4152static Object* Runtime_PushIfAbsent(Arguments args) {
4153 ASSERT(args.length() == 2);
4154 CONVERT_CHECKED(JSArray, array, args[0]);
4155 CONVERT_CHECKED(JSArray, element, args[1]);
4156 RUNTIME_ASSERT(array->HasFastElements());
4157 int length = Smi::cast(array->length())->value();
4158 FixedArray* elements = FixedArray::cast(array->elements());
4159 for (int i = 0; i < length; i++) {
4160 if (elements->get(i) == element) return Heap::false_value();
4161 }
4162 Object* obj = array->SetFastElement(length, element);
4163 if (obj->IsFailure()) return obj;
4164 return Heap::true_value();
4165}
4166
4167
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004168/**
4169 * A simple visitor visits every element of Array's.
4170 * The backend storage can be a fixed array for fast elements case,
4171 * or a dictionary for sparse array. Since Dictionary is a subtype
4172 * of FixedArray, the class can be used by both fast and slow cases.
4173 * The second parameter of the constructor, fast_elements, specifies
4174 * whether the storage is a FixedArray or Dictionary.
4175 *
4176 * An index limit is used to deal with the situation that a result array
4177 * length overflows 32-bit non-negative integer.
4178 */
4179class ArrayConcatVisitor {
4180 public:
4181 ArrayConcatVisitor(Handle<FixedArray> storage,
4182 uint32_t index_limit,
4183 bool fast_elements) :
4184 storage_(storage), index_limit_(index_limit),
4185 fast_elements_(fast_elements), index_offset_(0) { }
4186
4187 void visit(uint32_t i, Handle<Object> elm) {
4188 uint32_t index = i + index_offset_;
4189 if (index >= index_limit_) return;
4190
4191 if (fast_elements_) {
4192 ASSERT(index < static_cast<uint32_t>(storage_->length()));
4193 storage_->set(index, *elm);
4194
4195 } else {
4196 Handle<Dictionary> dict = Handle<Dictionary>::cast(storage_);
4197 Handle<Dictionary> result =
4198 Factory::DictionaryAtNumberPut(dict, index, elm);
4199 if (!result.is_identical_to(dict))
4200 storage_ = result;
4201 }
4202 }
4203
4204 void increase_index_offset(uint32_t delta) {
4205 index_offset_ += delta;
4206 }
4207
4208 private:
4209 Handle<FixedArray> storage_;
4210 uint32_t index_limit_;
4211 bool fast_elements_;
4212 uint32_t index_offset_;
4213};
4214
4215
4216/**
4217 * A helper function that visits elements of a JSObject. Only elements
4218 * whose index between 0 and range (exclusive) are visited.
4219 *
4220 * If the third parameter, visitor, is not NULL, the visitor is called
4221 * with parameters, 'visitor_index_offset + element index' and the element.
4222 *
4223 * It returns the number of visisted elements.
4224 */
4225static uint32_t IterateElements(Handle<JSObject> receiver,
4226 uint32_t range,
4227 ArrayConcatVisitor* visitor) {
4228 uint32_t num_of_elements = 0;
4229
4230 if (receiver->HasFastElements()) {
4231 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
4232 uint32_t len = elements->length();
4233 if (range < len) len = range;
4234
4235 for (uint32_t j = 0; j < len; j++) {
4236 Handle<Object> e(elements->get(j));
4237 if (!e->IsTheHole()) {
4238 num_of_elements++;
4239 if (visitor)
4240 visitor->visit(j, e);
4241 }
4242 }
4243
4244 } else {
4245 Handle<Dictionary> dict(receiver->element_dictionary());
4246 uint32_t capacity = dict->Capacity();
4247 for (uint32_t j = 0; j < capacity; j++) {
4248 Handle<Object> k(dict->KeyAt(j));
4249 if (dict->IsKey(*k)) {
4250 ASSERT(k->IsNumber());
4251 uint32_t index = static_cast<uint32_t>(k->Number());
4252 if (index < range) {
4253 num_of_elements++;
4254 if (visitor) {
4255 visitor->visit(index,
4256 Handle<Object>(dict->ValueAt(j)));
4257 }
4258 }
4259 }
4260 }
4261 }
4262
4263 return num_of_elements;
4264}
4265
4266
4267/**
4268 * A helper function that visits elements of an Array object, and elements
4269 * on its prototypes.
4270 *
4271 * Elements on prototypes are visited first, and only elements whose indices
4272 * less than Array length are visited.
4273 *
4274 * If a ArrayConcatVisitor object is given, the visitor is called with
4275 * parameters, element's index + visitor_index_offset and the element.
4276 */
4277static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
4278 ArrayConcatVisitor* visitor) {
4279 uint32_t range = static_cast<uint32_t>(array->length()->Number());
4280 Handle<Object> obj = array;
4281
4282 static const int kEstimatedPrototypes = 3;
4283 List< Handle<JSObject> > objects(kEstimatedPrototypes);
4284
4285 // Visit prototype first. If an element on the prototype is shadowed by
4286 // the inheritor using the same index, the ArrayConcatVisitor visits
4287 // the prototype element before the shadowing element.
4288 // The visitor can simply overwrite the old value by new value using
4289 // the same index. This follows Array::concat semantics.
4290 while (!obj->IsNull()) {
4291 objects.Add(Handle<JSObject>::cast(obj));
4292 obj = Handle<Object>(obj->GetPrototype());
4293 }
4294
4295 uint32_t nof_elements = 0;
4296 for (int i = objects.length() - 1; i >= 0; i--) {
4297 Handle<JSObject> obj = objects[i];
4298 nof_elements +=
4299 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
4300 }
4301
4302 return nof_elements;
4303}
4304
4305
4306/**
4307 * A helper function of Runtime_ArrayConcat.
4308 *
4309 * The first argument is an Array of arrays and objects. It is the
4310 * same as the arguments array of Array::concat JS function.
4311 *
4312 * If an argument is an Array object, the function visits array
4313 * elements. If an argument is not an Array object, the function
4314 * visits the object as if it is an one-element array.
4315 *
4316 * If the result array index overflows 32-bit integer, the rounded
4317 * non-negative number is used as new length. For example, if one
4318 * array length is 2^32 - 1, second array length is 1, the
4319 * concatenated array length is 0.
4320 */
4321static uint32_t IterateArguments(Handle<JSArray> arguments,
4322 ArrayConcatVisitor* visitor) {
4323 uint32_t visited_elements = 0;
4324 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4325
4326 for (uint32_t i = 0; i < num_of_args; i++) {
4327 Handle<Object> obj(arguments->GetElement(i));
4328 if (obj->IsJSArray()) {
4329 Handle<JSArray> array = Handle<JSArray>::cast(obj);
4330 uint32_t len = static_cast<uint32_t>(array->length()->Number());
4331 uint32_t nof_elements =
4332 IterateArrayAndPrototypeElements(array, visitor);
4333 // Total elements of array and its prototype chain can be more than
4334 // the array length, but ArrayConcat can only concatenate at most
4335 // the array length number of elements.
4336 visited_elements += (nof_elements > len) ? len : nof_elements;
4337 if (visitor) visitor->increase_index_offset(len);
4338
4339 } else {
4340 if (visitor) {
4341 visitor->visit(0, obj);
4342 visitor->increase_index_offset(1);
4343 }
4344 visited_elements++;
4345 }
4346 }
4347 return visited_elements;
4348}
4349
4350
4351/**
4352 * Array::concat implementation.
4353 * See ECMAScript 262, 15.4.4.4.
4354 */
4355static Object* Runtime_ArrayConcat(Arguments args) {
4356 ASSERT(args.length() == 1);
4357 HandleScope handle_scope;
4358
4359 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
4360 Handle<JSArray> arguments(arg_arrays);
4361
4362 // Pass 1: estimate the number of elements of the result
4363 // (it could be more than real numbers if prototype has elements).
4364 uint32_t result_length = 0;
4365 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4366
4367 { AssertNoAllocation nogc;
4368 for (uint32_t i = 0; i < num_of_args; i++) {
4369 Object* obj = arguments->GetElement(i);
4370 if (obj->IsJSArray()) {
4371 result_length +=
4372 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
4373 } else {
4374 result_length++;
4375 }
4376 }
4377 }
4378
4379 // Allocate an empty array, will set length and content later.
4380 Handle<JSArray> result = Factory::NewJSArray(0);
4381
4382 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
4383 // If estimated number of elements is more than half of length, a
4384 // fixed array (fast case) is more time and space-efficient than a
4385 // dictionary.
4386 bool fast_case = (estimate_nof_elements * 2) >= result_length;
4387
4388 Handle<FixedArray> storage;
4389 if (fast_case) {
4390 // The backing storage array must have non-existing elements to
4391 // preserve holes across concat operations.
4392 storage = Factory::NewFixedArrayWithHoles(result_length);
4393
4394 } else {
4395 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
4396 uint32_t at_least_space_for = estimate_nof_elements +
4397 (estimate_nof_elements >> 2);
4398 storage = Handle<FixedArray>::cast(
4399 Factory::NewDictionary(at_least_space_for));
4400 }
4401
4402 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
4403
4404 ArrayConcatVisitor visitor(storage, result_length, fast_case);
4405
4406 IterateArguments(arguments, &visitor);
4407
4408 result->set_length(*len);
4409 result->set_elements(*storage);
4410
4411 return *result;
4412}
4413
4414
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004415// This will not allocate (flatten the string), but it may run
4416// very slowly for very deeply nested ConsStrings. For debugging use only.
4417static Object* Runtime_GlobalPrint(Arguments args) {
4418 NoHandleAllocation ha;
4419 ASSERT(args.length() == 1);
4420
4421 CONVERT_CHECKED(String, string, args[0]);
4422 StringInputBuffer buffer(string);
4423 while (buffer.has_more()) {
4424 uint16_t character = buffer.GetNext();
4425 PrintF("%c", character);
4426 }
4427 return string;
4428}
4429
4430
4431static Object* Runtime_RemoveArrayHoles(Arguments args) {
4432 ASSERT(args.length() == 1);
4433 // Ignore the case if this is not a JSArray.
4434 if (!args[0]->IsJSArray()) return args[0];
4435 return JSArray::cast(args[0])->RemoveHoles();
4436}
4437
4438
4439// Move contents of argument 0 (an array) to argument 1 (an array)
4440static Object* Runtime_MoveArrayContents(Arguments args) {
4441 ASSERT(args.length() == 2);
4442 CONVERT_CHECKED(JSArray, from, args[0]);
4443 CONVERT_CHECKED(JSArray, to, args[1]);
4444 to->SetContent(FixedArray::cast(from->elements()));
4445 to->set_length(from->length());
4446 from->SetContent(Heap::empty_fixed_array());
4447 from->set_length(0);
4448 return to;
4449}
4450
4451
4452// How many elements does this array have?
4453static Object* Runtime_EstimateNumberOfElements(Arguments args) {
4454 ASSERT(args.length() == 1);
4455 CONVERT_CHECKED(JSArray, array, args[0]);
4456 HeapObject* elements = array->elements();
4457 if (elements->IsDictionary()) {
4458 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
4459 } else {
4460 return array->length();
4461 }
4462}
4463
4464
4465// Returns an array that tells you where in the [0, length) interval an array
4466// might have elements. Can either return keys or intervals. Keys can have
4467// gaps in (undefined). Intervals can also span over some undefined keys.
4468static Object* Runtime_GetArrayKeys(Arguments args) {
4469 ASSERT(args.length() == 2);
4470 HandleScope scope;
4471 CONVERT_CHECKED(JSArray, raw_array, args[0]);
4472 Handle<JSArray> array(raw_array);
4473 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004474 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 // Create an array and get all the keys into it, then remove all the
4476 // keys that are not integers in the range 0 to length-1.
4477 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
4478 int keys_length = keys->length();
4479 for (int i = 0; i < keys_length; i++) {
4480 Object* key = keys->get(i);
4481 uint32_t index;
4482 if (!Array::IndexFromObject(key, &index) || index >= length) {
4483 // Zap invalid keys.
4484 keys->set_undefined(i);
4485 }
4486 }
4487 return *Factory::NewJSArrayWithElements(keys);
4488 } else {
4489 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
4490 // -1 means start of array.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004491 single_interval->set(0,
4492 Smi::FromInt(-1),
4493 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494 Handle<Object> length_object =
4495 Factory::NewNumber(static_cast<double>(length));
4496 single_interval->set(1, *length_object);
4497 return *Factory::NewJSArrayWithElements(single_interval);
4498 }
4499}
4500
4501
4502// DefineAccessor takes an optional final argument which is the
4503// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
4504// to the way accessors are implemented, it is set for both the getter
4505// and setter on the first call to DefineAccessor and ignored on
4506// subsequent calls.
4507static Object* Runtime_DefineAccessor(Arguments args) {
4508 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
4509 // Compute attributes.
4510 PropertyAttributes attributes = NONE;
4511 if (args.length() == 5) {
4512 CONVERT_CHECKED(Smi, attrs, args[4]);
4513 int value = attrs->value();
4514 // Only attribute bits should be set.
4515 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4516 attributes = static_cast<PropertyAttributes>(value);
4517 }
4518
4519 CONVERT_CHECKED(JSObject, obj, args[0]);
4520 CONVERT_CHECKED(String, name, args[1]);
4521 CONVERT_CHECKED(Smi, flag, args[2]);
4522 CONVERT_CHECKED(JSFunction, fun, args[3]);
4523 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
4524}
4525
4526
4527static Object* Runtime_LookupAccessor(Arguments args) {
4528 ASSERT(args.length() == 3);
4529 CONVERT_CHECKED(JSObject, obj, args[0]);
4530 CONVERT_CHECKED(String, name, args[1]);
4531 CONVERT_CHECKED(Smi, flag, args[2]);
4532 return obj->LookupAccessor(name, flag->value() == 0);
4533}
4534
4535
4536// Helper functions for wrapping and unwrapping stack frame ids.
4537static Smi* WrapFrameId(StackFrame::Id id) {
4538 ASSERT(IsAligned(OffsetFrom(id), 4));
4539 return Smi::FromInt(id >> 2);
4540}
4541
4542
4543static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
4544 return static_cast<StackFrame::Id>(wrapped->value() << 2);
4545}
4546
4547
4548// Adds a JavaScript function as a debug event listener.
4549// args[0]: debug event listener function
4550// args[1]: object supplied during callback
4551static Object* Runtime_AddDebugEventListener(Arguments args) {
4552 ASSERT(args.length() == 2);
4553 // Convert the parameters to API objects to call the API function for adding
4554 // a JavaScript function as debug event listener.
4555 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4556 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4557 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
4558 v8::Debug::AddDebugEventListener(fun, data);
4559
4560 return Heap::undefined_value();
4561}
4562
4563
4564// Removes a JavaScript function debug event listener.
4565// args[0]: debug event listener function
4566static Object* Runtime_RemoveDebugEventListener(Arguments args) {
4567 ASSERT(args.length() == 1);
4568 // Convert the parameter to an API object to call the API function for
4569 // removing a JavaScript function debug event listener.
4570 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4571 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4572 v8::Debug::RemoveDebugEventListener(fun);
4573
4574 return Heap::undefined_value();
4575}
4576
4577
4578static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004579 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 StackGuard::DebugBreak();
4581 return Heap::undefined_value();
4582}
4583
4584
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004585// Find the length of the prototype chain that is to to handled as one. If a
4586// prototype object is hidden it is to be viewed as part of the the object it
4587// is prototype for.
4588static int LocalPrototypeChainLength(JSObject* obj) {
4589 int count = 1;
4590 Object* proto = obj->GetPrototype();
4591 while (proto->IsJSObject() &&
4592 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4593 count++;
4594 proto = JSObject::cast(proto)->GetPrototype();
4595 }
4596 return count;
4597}
4598
4599
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004600static Object* DebugLookupResultValue(Object* receiver, LookupResult* result,
ager@chromium.org32912102009-01-16 10:38:43 +00004601 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004602 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 switch (result->type()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004604 case NORMAL: {
4605 Dictionary* dict =
4606 JSObject::cast(result->holder())->property_dictionary();
4607 value = dict->ValueAt(result->GetDictionaryEntry());
4608 if (value->IsTheHole()) {
4609 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 }
4611 return value;
4612 }
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004613 case FIELD:
4614 value =
4615 JSObject::cast(
4616 result->holder())->FastPropertyAt(result->GetFieldIndex());
4617 if (value->IsTheHole()) {
4618 return Heap::undefined_value();
4619 }
4620 return value;
4621 case CONSTANT_FUNCTION:
4622 return result->GetConstantFunction();
4623 case CALLBACKS: {
4624 Object* structure = result->GetCallbackObject();
4625 if (structure->IsProxy()) {
4626 AccessorDescriptor* callback =
4627 reinterpret_cast<AccessorDescriptor*>(
4628 Proxy::cast(structure)->proxy());
4629 value = (callback->getter)(receiver, callback->data);
4630 if (value->IsFailure()) {
4631 value = Top::pending_exception();
4632 Top::clear_pending_exception();
4633 if (caught_exception != NULL) {
4634 *caught_exception = true;
4635 }
4636 }
4637 return value;
4638 } else {
4639 return Heap::undefined_value();
4640 }
4641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004643 case MAP_TRANSITION:
4644 case CONSTANT_TRANSITION:
4645 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646 return Heap::undefined_value();
4647 default:
4648 UNREACHABLE();
4649 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004650 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651 return Heap::undefined_value();
4652}
4653
4654
ager@chromium.org32912102009-01-16 10:38:43 +00004655// Get debugger related details for an object property.
4656// args[0]: object holding property
4657// args[1]: name of the property
4658//
4659// The array returned contains the following information:
4660// 0: Property value
4661// 1: Property details
4662// 2: Property value is exception
4663// 3: Getter function if defined
4664// 4: Setter function if defined
4665// Items 2-4 are only filled if the property has either a getter or a setter
4666// defined through __defineGetter__ and/or __defineSetter__.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004667static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668 HandleScope scope;
4669
4670 ASSERT(args.length() == 2);
4671
4672 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4673 CONVERT_ARG_CHECKED(String, name, 1);
4674
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004675 // Skip the global proxy as it has no properties and always delegates to the
4676 // real global object.
4677 if (obj->IsJSGlobalProxy()) {
4678 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4679 }
4680
4681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004682 // Check if the name is trivially convertible to an index and get the element
4683 // if so.
4684 uint32_t index;
4685 if (name->AsArrayIndex(&index)) {
4686 Handle<FixedArray> details = Factory::NewFixedArray(2);
4687 details->set(0, Runtime::GetElementOrCharAt(obj, index));
4688 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
4689 return *Factory::NewJSArrayWithElements(details);
4690 }
4691
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004692 // Find the number of objects making up this.
4693 int length = LocalPrototypeChainLength(*obj);
4694
4695 // Try local lookup on each of the objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004697 Handle<JSObject> jsproto = obj;
4698 for (int i = 0; i < length; i++) {
4699 jsproto->LocalLookup(*name, &result);
4700 if (result.IsProperty()) {
4701 break;
4702 }
4703 if (i < length - 1) {
4704 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4705 }
4706 }
4707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 if (result.IsProperty()) {
ager@chromium.org32912102009-01-16 10:38:43 +00004709 bool caught_exception = false;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004710 Handle<Object> value(DebugLookupResultValue(*obj, &result,
ager@chromium.org32912102009-01-16 10:38:43 +00004711 &caught_exception));
4712 // If the callback object is a fixed array then it contains JavaScript
4713 // getter and/or setter.
4714 bool hasJavaScriptAccessors = result.type() == CALLBACKS &&
4715 result.GetCallbackObject()->IsFixedArray();
4716 Handle<FixedArray> details =
4717 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 details->set(0, *value);
4719 details->set(1, result.GetPropertyDetails().AsSmi());
ager@chromium.org32912102009-01-16 10:38:43 +00004720 if (hasJavaScriptAccessors) {
4721 details->set(2,
4722 caught_exception ? Heap::true_value() : Heap::false_value());
4723 details->set(3, FixedArray::cast(result.GetCallbackObject())->get(0));
4724 details->set(4, FixedArray::cast(result.GetCallbackObject())->get(1));
4725 }
4726
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727 return *Factory::NewJSArrayWithElements(details);
4728 }
4729 return Heap::undefined_value();
4730}
4731
4732
4733static Object* Runtime_DebugGetProperty(Arguments args) {
4734 HandleScope scope;
4735
4736 ASSERT(args.length() == 2);
4737
4738 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4739 CONVERT_ARG_CHECKED(String, name, 1);
4740
4741 LookupResult result;
4742 obj->Lookup(*name, &result);
4743 if (result.IsProperty()) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00004744 return DebugLookupResultValue(*obj, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004745 }
4746 return Heap::undefined_value();
4747}
4748
4749
4750// Return the names of the local named properties.
4751// args[0]: object
4752static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
4753 HandleScope scope;
4754 ASSERT(args.length() == 1);
4755 if (!args[0]->IsJSObject()) {
4756 return Heap::undefined_value();
4757 }
4758 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4759
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004760 // Skip the global proxy as it has no properties and always delegates to the
4761 // real global object.
4762 if (obj->IsJSGlobalProxy()) {
4763 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4764 }
4765
4766 // Find the number of objects making up this.
4767 int length = LocalPrototypeChainLength(*obj);
4768
4769 // Find the number of local properties for each of the objects.
4770 int* local_property_count = NewArray<int>(length);
4771 int total_property_count = 0;
4772 Handle<JSObject> jsproto = obj;
4773 for (int i = 0; i < length; i++) {
4774 int n;
4775 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4776 local_property_count[i] = n;
4777 total_property_count += n;
4778 if (i < length - 1) {
4779 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4780 }
4781 }
4782
4783 // Allocate an array with storage for all the property names.
4784 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4785
4786 // Get the property names.
4787 jsproto = obj;
4788 for (int i = 0; i < length; i++) {
4789 jsproto->GetLocalPropertyNames(*names,
4790 i == 0 ? 0 : local_property_count[i - 1]);
4791 if (i < length - 1) {
4792 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4793 }
4794 }
4795
4796 DeleteArray(local_property_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 return *Factory::NewJSArrayWithElements(names);
4798}
4799
4800
4801// Return the names of the local indexed properties.
4802// args[0]: object
4803static Object* Runtime_DebugLocalElementNames(Arguments args) {
4804 HandleScope scope;
4805 ASSERT(args.length() == 1);
4806 if (!args[0]->IsJSObject()) {
4807 return Heap::undefined_value();
4808 }
4809 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4810
4811 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4812 Handle<FixedArray> names = Factory::NewFixedArray(n);
4813 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4814 return *Factory::NewJSArrayWithElements(names);
4815}
4816
4817
4818// Return the property type calculated from the property details.
4819// args[0]: smi with property details.
4820static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
4821 ASSERT(args.length() == 1);
4822 CONVERT_CHECKED(Smi, details, args[0]);
4823 PropertyType type = PropertyDetails(details).type();
4824 return Smi::FromInt(static_cast<int>(type));
4825}
4826
4827
4828// Return the property attribute calculated from the property details.
4829// args[0]: smi with property details.
4830static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
4831 ASSERT(args.length() == 1);
4832 CONVERT_CHECKED(Smi, details, args[0]);
4833 PropertyAttributes attributes = PropertyDetails(details).attributes();
4834 return Smi::FromInt(static_cast<int>(attributes));
4835}
4836
4837
4838// Return the property insertion index calculated from the property details.
4839// args[0]: smi with property details.
4840static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
4841 ASSERT(args.length() == 1);
4842 CONVERT_CHECKED(Smi, details, args[0]);
4843 int index = PropertyDetails(details).index();
4844 return Smi::FromInt(index);
4845}
4846
4847
4848// Return information on whether an object has a named or indexed interceptor.
4849// args[0]: object
4850static Object* Runtime_DebugInterceptorInfo(Arguments args) {
4851 HandleScope scope;
4852 ASSERT(args.length() == 1);
4853 if (!args[0]->IsJSObject()) {
4854 return Smi::FromInt(0);
4855 }
4856 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4857
4858 int result = 0;
4859 if (obj->HasNamedInterceptor()) result |= 2;
4860 if (obj->HasIndexedInterceptor()) result |= 1;
4861
4862 return Smi::FromInt(result);
4863}
4864
4865
4866// Return property names from named interceptor.
4867// args[0]: object
4868static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
4869 HandleScope scope;
4870 ASSERT(args.length() == 1);
4871 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872
ager@chromium.org32912102009-01-16 10:38:43 +00004873 if (obj->HasNamedInterceptor()) {
4874 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4875 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4876 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 return Heap::undefined_value();
4878}
4879
4880
4881// Return element names from indexed interceptor.
4882// args[0]: object
4883static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
4884 HandleScope scope;
4885 ASSERT(args.length() == 1);
4886 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887
ager@chromium.org32912102009-01-16 10:38:43 +00004888 if (obj->HasIndexedInterceptor()) {
4889 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4890 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004892 return Heap::undefined_value();
4893}
4894
4895
4896// Return property value from named interceptor.
4897// args[0]: object
4898// args[1]: property name
4899static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
4900 HandleScope scope;
4901 ASSERT(args.length() == 2);
4902 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4903 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4904 CONVERT_ARG_CHECKED(String, name, 1);
4905
4906 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004907 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908}
4909
4910
4911// Return element value from indexed interceptor.
4912// args[0]: object
4913// args[1]: index
4914static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
4915 HandleScope scope;
4916 ASSERT(args.length() == 2);
4917 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4918 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4919 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
4920
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004921 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922}
4923
4924
4925static Object* Runtime_CheckExecutionState(Arguments args) {
4926 ASSERT(args.length() >= 1);
4927 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00004928 // Check that the break id is valid.
4929 if (Top::break_id() == 0 || break_id != Top::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930 return Top::Throw(Heap::illegal_execution_state_symbol());
4931 }
4932
4933 return Heap::true_value();
4934}
4935
4936
4937static Object* Runtime_GetFrameCount(Arguments args) {
4938 HandleScope scope;
4939 ASSERT(args.length() == 1);
4940
4941 // Check arguments.
4942 Object* result = Runtime_CheckExecutionState(args);
4943 if (result->IsFailure()) return result;
4944
4945 // Count all frames which are relevant to debugging stack trace.
4946 int n = 0;
4947 StackFrame::Id id = Top::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00004948 if (id == StackFrame::NO_ID) {
4949 // If there is no JavaScript stack frame count is 0.
4950 return Smi::FromInt(0);
4951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
4953 return Smi::FromInt(n);
4954}
4955
4956
4957static const int kFrameDetailsFrameIdIndex = 0;
4958static const int kFrameDetailsReceiverIndex = 1;
4959static const int kFrameDetailsFunctionIndex = 2;
4960static const int kFrameDetailsArgumentCountIndex = 3;
4961static const int kFrameDetailsLocalCountIndex = 4;
4962static const int kFrameDetailsSourcePositionIndex = 5;
4963static const int kFrameDetailsConstructCallIndex = 6;
4964static const int kFrameDetailsDebuggerFrameIndex = 7;
4965static const int kFrameDetailsFirstDynamicIndex = 8;
4966
4967// Return an array with frame details
4968// args[0]: number: break id
4969// args[1]: number: frame index
4970//
4971// The array returned contains the following information:
4972// 0: Frame id
4973// 1: Receiver
4974// 2: Function
4975// 3: Argument count
4976// 4: Local count
4977// 5: Source position
4978// 6: Constructor call
4979// 7: Debugger frame
4980// Arguments name, value
4981// Locals name, value
4982static Object* Runtime_GetFrameDetails(Arguments args) {
4983 HandleScope scope;
4984 ASSERT(args.length() == 2);
4985
4986 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004987 Object* check = Runtime_CheckExecutionState(args);
4988 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004989 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
4990
4991 // Find the relevant frame with the requested index.
4992 StackFrame::Id id = Top::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00004993 if (id == StackFrame::NO_ID) {
4994 // If there are no JavaScript stack frames return undefined.
4995 return Heap::undefined_value();
4996 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 int count = 0;
4998 JavaScriptFrameIterator it(id);
4999 for (; !it.done(); it.Advance()) {
5000 if (count == index) break;
5001 count++;
5002 }
5003 if (it.done()) return Heap::undefined_value();
5004
5005 // Traverse the saved contexts chain to find the active context for the
5006 // selected frame.
5007 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005008 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005009 save = save->prev();
5010 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005011 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005012
5013 // Get the frame id.
5014 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
5015
5016 // Find source position.
5017 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
5018
5019 // Check for constructor frame.
5020 bool constructor = it.frame()->IsConstructor();
5021
5022 // Get code and read scope info from it for local variable information.
5023 Handle<Code> code(it.frame()->FindCode());
5024 ScopeInfo<> info(*code);
5025
5026 // Get the context.
5027 Handle<Context> context(Context::cast(it.frame()->context()));
5028
5029 // Get the locals names and values into a temporary array.
5030 //
5031 // TODO(1240907): Hide compiler-introduced stack variables
5032 // (e.g. .result)? For users of the debugger, they will probably be
5033 // confusing.
5034 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
5035 for (int i = 0; i < info.NumberOfLocals(); i++) {
5036 // Name of the local.
5037 locals->set(i * 2, *info.LocalName(i));
5038
5039 // Fetch the value of the local - either from the stack or from a
5040 // heap-allocated context.
5041 if (i < info.number_of_stack_slots()) {
5042 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
5043 } else {
5044 Handle<String> name = info.LocalName(i);
5045 // Traverse the context chain to the function context as all local
5046 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005047 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005048 context = Handle<Context>(context->previous());
5049 }
5050 ASSERT(context->is_function_context());
5051 locals->set(i * 2 + 1,
5052 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
5053 NULL)));
5054 }
5055 }
5056
5057 // Now advance to the arguments adapter frame (if any). If contains all
5058 // the provided parameters and
5059
5060 // Now advance to the arguments adapter frame (if any). It contains all
5061 // the provided parameters whereas the function frame always have the number
5062 // of arguments matching the functions parameters. The rest of the
5063 // information (except for what is collected above) is the same.
5064 it.AdvanceToArgumentsFrame();
5065
5066 // Find the number of arguments to fill. At least fill the number of
5067 // parameters for the function and fill more if more parameters are provided.
5068 int argument_count = info.number_of_parameters();
5069 if (argument_count < it.frame()->GetProvidedParametersCount()) {
5070 argument_count = it.frame()->GetProvidedParametersCount();
5071 }
5072
5073 // Calculate the size of the result.
5074 int details_size = kFrameDetailsFirstDynamicIndex +
5075 2 * (argument_count + info.NumberOfLocals());
5076 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
5077
5078 // Add the frame id.
5079 details->set(kFrameDetailsFrameIdIndex, *frame_id);
5080
5081 // Add the function (same as in function frame).
5082 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
5083
5084 // Add the arguments count.
5085 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
5086
5087 // Add the locals count
5088 details->set(kFrameDetailsLocalCountIndex,
5089 Smi::FromInt(info.NumberOfLocals()));
5090
5091 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00005092 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
5094 } else {
5095 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
5096 }
5097
5098 // Add the constructor information.
5099 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
5100
5101 // Add information on whether this frame is invoked in the debugger context.
5102 details->set(kFrameDetailsDebuggerFrameIndex,
5103 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
5104
5105 // Fill the dynamic part.
5106 int details_index = kFrameDetailsFirstDynamicIndex;
5107
5108 // Add arguments name and value.
5109 for (int i = 0; i < argument_count; i++) {
5110 // Name of the argument.
5111 if (i < info.number_of_parameters()) {
5112 details->set(details_index++, *info.parameter_name(i));
5113 } else {
5114 details->set(details_index++, Heap::undefined_value());
5115 }
5116
5117 // Parameter value.
5118 if (i < it.frame()->GetProvidedParametersCount()) {
5119 details->set(details_index++, it.frame()->GetParameter(i));
5120 } else {
5121 details->set(details_index++, Heap::undefined_value());
5122 }
5123 }
5124
5125 // Add locals name and value from the temporary copy from the function frame.
5126 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
5127 details->set(details_index++, locals->get(i));
5128 }
5129
5130 // Add the receiver (same as in function frame).
5131 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
5132 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
5133 Handle<Object> receiver(it.frame()->receiver());
5134 if (!receiver->IsJSObject()) {
5135 // If the receiver is NOT a JSObject we have hit an optimization
5136 // where a value object is not converted into a wrapped JS objects.
5137 // To hide this optimization from the debugger, we wrap the receiver
5138 // by creating correct wrapper object based on the calling frame's
5139 // global context.
5140 it.Advance();
5141 Handle<Context> calling_frames_global_context(
5142 Context::cast(Context::cast(it.frame()->context())->global_context()));
5143 receiver = Factory::ToObject(receiver, calling_frames_global_context);
5144 }
5145 details->set(kFrameDetailsReceiverIndex, *receiver);
5146
5147 ASSERT_EQ(details_size, details_index);
5148 return *Factory::NewJSArrayWithElements(details);
5149}
5150
5151
5152static Object* Runtime_GetCFrames(Arguments args) {
5153 HandleScope scope;
5154 ASSERT(args.length() == 1);
5155 Object* result = Runtime_CheckExecutionState(args);
5156 if (result->IsFailure()) return result;
5157
5158 static const int kMaxCFramesSize = 200;
5159 OS::StackFrame frames[kMaxCFramesSize];
5160 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
5161 if (frames_count == OS::kStackWalkError) {
5162 return Heap::undefined_value();
5163 }
5164
5165 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
5166 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
5167 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
5168 for (int i = 0; i < frames_count; i++) {
5169 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
5170 frame_value->SetProperty(
5171 *address_str,
5172 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
5173 NONE);
5174
5175 // Get the stack walk text for this frame.
5176 Handle<String> frame_text;
5177 if (strlen(frames[i].text) > 0) {
5178 Vector<const char> str(frames[i].text, strlen(frames[i].text));
5179 frame_text = Factory::NewStringFromAscii(str);
5180 }
5181
5182 if (!frame_text.is_null()) {
5183 frame_value->SetProperty(*text_str, *frame_text, NONE);
5184 }
5185
5186 frames_array->set(i, *frame_value);
5187 }
5188 return *Factory::NewJSArrayWithElements(frames_array);
5189}
5190
5191
5192static Object* Runtime_GetBreakLocations(Arguments args) {
5193 HandleScope scope;
5194 ASSERT(args.length() == 1);
5195
5196 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
5197 Handle<SharedFunctionInfo> shared(raw_fun->shared());
5198 // Find the number of break points
5199 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
5200 if (break_locations->IsUndefined()) return Heap::undefined_value();
5201 // Return array as JS array
5202 return *Factory::NewJSArrayWithElements(
5203 Handle<FixedArray>::cast(break_locations));
5204}
5205
5206
5207// Set a break point in a function
5208// args[0]: function
5209// args[1]: number: break source position (within the function source)
5210// args[2]: number: break point object
5211static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
5212 HandleScope scope;
5213 ASSERT(args.length() == 3);
5214 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
5215 Handle<SharedFunctionInfo> shared(raw_fun->shared());
5216 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
5217 RUNTIME_ASSERT(source_position >= 0);
5218 Handle<Object> break_point_object_arg = args.at<Object>(2);
5219
5220 // Set break point.
5221 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
5222
5223 return Heap::undefined_value();
5224}
5225
5226
5227static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
5228 int position) {
5229 // Iterate the heap looking for SharedFunctionInfo generated from the
5230 // script. The inner most SharedFunctionInfo containing the source position
5231 // for the requested break point is found.
5232 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
5233 // which is found is not compiled it is compiled and the heap is iterated
5234 // again as the compilation might create inner functions from the newly
5235 // compiled function and the actual requested break point might be in one of
5236 // these functions.
5237 bool done = false;
5238 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00005239 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 Handle<SharedFunctionInfo> target;
5241 // The current candidate for the last function in script:
5242 Handle<SharedFunctionInfo> last;
5243 while (!done) {
5244 HeapIterator iterator;
5245 while (iterator.has_next()) {
5246 HeapObject* obj = iterator.next();
5247 ASSERT(obj != NULL);
5248 if (obj->IsSharedFunctionInfo()) {
5249 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
5250 if (shared->script() == *script) {
5251 // If the SharedFunctionInfo found has the requested script data and
5252 // contains the source position it is a candidate.
5253 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00005254 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005255 start_position = shared->start_position();
5256 }
5257 if (start_position <= position &&
5258 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00005259 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 // candidate this is the new candidate.
5261 if (target.is_null()) {
5262 target_start_position = start_position;
5263 target = shared;
5264 } else {
5265 if (target_start_position < start_position &&
5266 shared->end_position() < target->end_position()) {
5267 target_start_position = start_position;
5268 target = shared;
5269 }
5270 }
5271 }
5272
5273 // Keep track of the last function in the script.
5274 if (last.is_null() ||
5275 shared->end_position() > last->start_position()) {
5276 last = shared;
5277 }
5278 }
5279 }
5280 }
5281
5282 // Make sure some candidate is selected.
5283 if (target.is_null()) {
5284 if (!last.is_null()) {
5285 // Position after the last function - use last.
5286 target = last;
5287 } else {
5288 // Unable to find function - possibly script without any function.
5289 return Heap::undefined_value();
5290 }
5291 }
5292
5293 // If the candidate found is compiled we are done. NOTE: when lazy
5294 // compilation of inner functions is introduced some additional checking
5295 // needs to be done here to compile inner functions.
5296 done = target->is_compiled();
5297 if (!done) {
5298 // If the candidate is not compiled compile it to reveal any inner
5299 // functions which might contain the requested source position.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005300 CompileLazyShared(target, KEEP_EXCEPTION, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005301 }
5302 }
5303
5304 return *target;
5305}
5306
5307
5308// Change the state of a break point in a script. NOTE: Regarding performance
5309// see the NOTE for GetScriptFromScriptData.
5310// args[0]: script to set break point in
5311// args[1]: number: break source position (within the script source)
5312// args[2]: number: break point object
5313static Object* Runtime_SetScriptBreakPoint(Arguments args) {
5314 HandleScope scope;
5315 ASSERT(args.length() == 3);
5316 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
5317 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
5318 RUNTIME_ASSERT(source_position >= 0);
5319 Handle<Object> break_point_object_arg = args.at<Object>(2);
5320
5321 // Get the script from the script wrapper.
5322 RUNTIME_ASSERT(wrapper->value()->IsScript());
5323 Handle<Script> script(Script::cast(wrapper->value()));
5324
5325 Object* result = FindSharedFunctionInfoInScript(script, source_position);
5326 if (!result->IsUndefined()) {
5327 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
5328 // Find position within function. The script position might be before the
5329 // source position of the first function.
5330 int position;
5331 if (shared->start_position() > source_position) {
5332 position = 0;
5333 } else {
5334 position = source_position - shared->start_position();
5335 }
5336 Debug::SetBreakPoint(shared, position, break_point_object_arg);
5337 }
5338 return Heap::undefined_value();
5339}
5340
5341
5342// Clear a break point
5343// args[0]: number: break point object
5344static Object* Runtime_ClearBreakPoint(Arguments args) {
5345 HandleScope scope;
5346 ASSERT(args.length() == 1);
5347 Handle<Object> break_point_object_arg = args.at<Object>(0);
5348
5349 // Clear break point.
5350 Debug::ClearBreakPoint(break_point_object_arg);
5351
5352 return Heap::undefined_value();
5353}
5354
5355
5356// Change the state of break on exceptions
5357// args[0]: boolean indicating uncaught exceptions
5358// args[1]: boolean indicating on/off
5359static Object* Runtime_ChangeBreakOnException(Arguments args) {
5360 HandleScope scope;
5361 ASSERT(args.length() == 2);
5362 ASSERT(args[0]->IsNumber());
5363 ASSERT(args[1]->IsBoolean());
5364
5365 // Update break point state
5366 ExceptionBreakType type =
5367 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
5368 bool enable = args[1]->ToBoolean()->IsTrue();
5369 Debug::ChangeBreakOnException(type, enable);
5370 return Heap::undefined_value();
5371}
5372
5373
5374// Prepare for stepping
5375// args[0]: break id for checking execution state
5376// args[1]: step action from the enumeration StepAction
5377// args[2]: number of times to perform the step
5378static Object* Runtime_PrepareStep(Arguments args) {
5379 HandleScope scope;
5380 ASSERT(args.length() == 3);
5381 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005382 Object* check = Runtime_CheckExecutionState(args);
5383 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
5385 return Top::Throw(Heap::illegal_argument_symbol());
5386 }
5387
5388 // Get the step action and check validity.
5389 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
5390 if (step_action != StepIn &&
5391 step_action != StepNext &&
5392 step_action != StepOut &&
5393 step_action != StepInMin &&
5394 step_action != StepMin) {
5395 return Top::Throw(Heap::illegal_argument_symbol());
5396 }
5397
5398 // Get the number of steps.
5399 int step_count = NumberToInt32(args[2]);
5400 if (step_count < 1) {
5401 return Top::Throw(Heap::illegal_argument_symbol());
5402 }
5403
5404 // Prepare step.
5405 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
5406 return Heap::undefined_value();
5407}
5408
5409
5410// Clear all stepping set by PrepareStep.
5411static Object* Runtime_ClearStepping(Arguments args) {
5412 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005413 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005414 Debug::ClearStepping();
5415 return Heap::undefined_value();
5416}
5417
5418
5419// Creates a copy of the with context chain. The copy of the context chain is
5420// is linked to the function context supplied.
5421static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
5422 Handle<Context> function_context) {
5423 // At the bottom of the chain. Return the function context to link to.
5424 if (context_chain->is_function_context()) {
5425 return function_context;
5426 }
5427
5428 // Recursively copy the with contexts.
5429 Handle<Context> previous(context_chain->previous());
5430 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
5431 return Factory::NewWithContext(
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00005432 CopyWithContextChain(function_context, previous),
5433 extension,
5434 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435}
5436
5437
5438// Helper function to find or create the arguments object for
5439// Runtime_DebugEvaluate.
5440static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
5441 Handle<JSFunction> function,
5442 Handle<Code> code,
5443 const ScopeInfo<>* sinfo,
5444 Handle<Context> function_context) {
5445 // Try to find the value of 'arguments' to pass as parameter. If it is not
5446 // found (that is the debugged function does not reference 'arguments' and
5447 // does not support eval) then create an 'arguments' object.
5448 int index;
5449 if (sinfo->number_of_stack_slots() > 0) {
5450 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
5451 if (index != -1) {
5452 return Handle<Object>(frame->GetExpression(index));
5453 }
5454 }
5455
5456 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
5457 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
5458 NULL);
5459 if (index != -1) {
5460 return Handle<Object>(function_context->get(index));
5461 }
5462 }
5463
5464 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005465 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
5466 Handle<FixedArray> array = Factory::NewFixedArray(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005467 WriteBarrierMode mode = array->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005468 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005469 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005471 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005472 return arguments;
5473}
5474
5475
5476// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00005477// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005478// extension part has all the parameters and locals of the function on the
5479// stack frame. A function which calls eval with the code to evaluate is then
5480// compiled in this context and called in this context. As this context
5481// replaces the context of the function on the stack frame a new (empty)
5482// function is created as well to be used as the closure for the context.
5483// This function and the context acts as replacements for the function on the
5484// stack frame presenting the same view of the values of parameters and
5485// local variables as if the piece of JavaScript was evaluated at the point
5486// where the function on the stack frame is currently stopped.
5487static Object* Runtime_DebugEvaluate(Arguments args) {
5488 HandleScope scope;
5489
5490 // Check the execution state and decode arguments frame and source to be
5491 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005492 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005493 Object* check_result = Runtime_CheckExecutionState(args);
5494 if (check_result->IsFailure()) return check_result;
5495 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
5496 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005497 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
5498
5499 // Handle the processing of break.
5500 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501
5502 // Get the frame where the debugging is performed.
5503 StackFrame::Id id = UnwrapFrameId(wrapped_id);
5504 JavaScriptFrameIterator it(id);
5505 JavaScriptFrame* frame = it.frame();
5506 Handle<JSFunction> function(JSFunction::cast(frame->function()));
5507 Handle<Code> code(function->code());
5508 ScopeInfo<> sinfo(*code);
5509
5510 // Traverse the saved contexts chain to find the active context for the
5511 // selected frame.
5512 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005513 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514 save = save->prev();
5515 }
5516 ASSERT(save != NULL);
5517 SaveContext savex;
5518 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519
5520 // Create the (empty) function replacing the function on the stack frame for
5521 // the purpose of evaluating in the context created below. It is important
5522 // that this function does not describe any parameters and local variables
5523 // in the context. If it does then this will cause problems with the lookup
5524 // in Context::Lookup, where context slots for parameters and local variables
5525 // are looked at before the extension object.
5526 Handle<JSFunction> go_between =
5527 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
5528 go_between->set_context(function->context());
5529#ifdef DEBUG
5530 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
5531 ASSERT(go_between_sinfo.number_of_parameters() == 0);
5532 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
5533#endif
5534
5535 // Allocate and initialize a context extension object with all the
5536 // arguments, stack locals heap locals and extension properties of the
5537 // debugged function.
5538 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
5539 // First fill all parameters to the context extension.
5540 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
5541 SetProperty(context_ext,
5542 sinfo.parameter_name(i),
5543 Handle<Object>(frame->GetParameter(i)), NONE);
5544 }
5545 // Second fill all stack locals to the context extension.
5546 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
5547 SetProperty(context_ext,
5548 sinfo.stack_slot_name(i),
5549 Handle<Object>(frame->GetExpression(i)), NONE);
5550 }
5551 // Third fill all context locals to the context extension.
5552 Handle<Context> frame_context(Context::cast(frame->context()));
5553 Handle<Context> function_context(frame_context->fcontext());
5554 for (int i = Context::MIN_CONTEXT_SLOTS;
5555 i < sinfo.number_of_context_slots();
5556 ++i) {
5557 int context_index =
5558 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
5559 SetProperty(context_ext,
5560 sinfo.context_slot_name(i),
5561 Handle<Object>(function_context->get(context_index)), NONE);
5562 }
5563 // Finally copy any properties from the function context extension. This will
5564 // be variables introduced by eval.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005565 if (function_context->has_extension() &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566 !function_context->IsGlobalContext()) {
5567 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
5568 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
5569 for (int i = 0; i < keys->length(); i++) {
5570 // Names of variables introduced by eval are strings.
5571 ASSERT(keys->get(i)->IsString());
5572 Handle<String> key(String::cast(keys->get(i)));
5573 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
5574 }
5575 }
5576
5577 // Allocate a new context for the debug evaluation and set the extension
5578 // object build.
5579 Handle<Context> context =
5580 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
5581 context->set_extension(*context_ext);
5582 // Copy any with contexts present and chain them in front of this context.
5583 context = CopyWithContextChain(frame_context, context);
5584
5585 // Wrap the evaluation statement in a new function compiled in the newly
5586 // created context. The function has one parameter which has to be called
5587 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00005588 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589 // function(arguments,__source__) {return eval(__source__);}
5590 static const char* source_str =
5591 "function(arguments,__source__){return eval(__source__);}";
5592 static const int source_str_length = strlen(source_str);
5593 Handle<String> function_source =
5594 Factory::NewStringFromAscii(Vector<const char>(source_str,
5595 source_str_length));
5596 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00005597 Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005598 if (boilerplate.is_null()) return Failure::Exception();
5599 Handle<JSFunction> compiled_function =
5600 Factory::NewFunctionFromBoilerplate(boilerplate, context);
5601
5602 // Invoke the result of the compilation to get the evaluation function.
5603 bool has_pending_exception;
5604 Handle<Object> receiver(frame->receiver());
5605 Handle<Object> evaluation_function =
5606 Execution::Call(compiled_function, receiver, 0, NULL,
5607 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005608 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609
5610 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
5611 function_context);
5612
5613 // Invoke the evaluation function and return the result.
5614 const int argc = 2;
5615 Object** argv[argc] = { arguments.location(),
5616 Handle<Object>::cast(source).location() };
5617 Handle<Object> result =
5618 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
5619 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005620 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005621 return *result;
5622}
5623
5624
5625static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
5626 HandleScope scope;
5627
5628 // Check the execution state and decode arguments frame and source to be
5629 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005630 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005631 Object* check_result = Runtime_CheckExecutionState(args);
5632 if (check_result->IsFailure()) return check_result;
5633 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005634 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
5635
5636 // Handle the processing of break.
5637 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005638
5639 // Enter the top context from before the debugger was invoked.
5640 SaveContext save;
5641 SaveContext* top = &save;
5642 while (top != NULL && *top->context() == *Debug::debug_context()) {
5643 top = top->prev();
5644 }
5645 if (top != NULL) {
5646 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647 }
5648
5649 // Get the global context now set to the top context from before the
5650 // debugger was invoked.
5651 Handle<Context> context = Top::global_context();
5652
5653 // Compile the source to be evaluated.
ager@chromium.org236ad962008-09-25 09:45:57 +00005654 Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005655 if (boilerplate.is_null()) return Failure::Exception();
5656 Handle<JSFunction> compiled_function =
5657 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
5658 context));
5659
5660 // Invoke the result of the compilation to get the evaluation function.
5661 bool has_pending_exception;
5662 Handle<Object> receiver = Top::global();
5663 Handle<Object> result =
5664 Execution::Call(compiled_function, receiver, 0, NULL,
5665 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005666 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005667 return *result;
5668}
5669
5670
5671// Helper function used by Runtime_DebugGetLoadedScripts below.
5672static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
5673 NoHandleAllocation ha;
5674 AssertNoAllocation no_alloc;
5675
5676 // Get hold of the current empty script.
5677 Context* context = Top::context()->global_context();
5678 Script* empty = context->empty_script();
5679
5680 // Scan heap for Script objects.
5681 int count = 0;
5682 HeapIterator iterator;
5683 while (iterator.has_next()) {
5684 HeapObject* obj = iterator.next();
5685 ASSERT(obj != NULL);
5686 if (obj->IsScript() && obj != empty) {
5687 if (instances != NULL && count < instances_size) {
5688 instances->set(count, obj);
5689 }
5690 count++;
5691 }
5692 }
5693
5694 return count;
5695}
5696
5697
5698static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
5699 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005700 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005701
5702 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
ager@chromium.org32912102009-01-16 10:38:43 +00005703 // rid of all the cached script wrappers and the second gets rid of the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005704 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005705 Heap::CollectAllGarbage();
5706 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005707
5708 // Get the number of scripts.
5709 int count;
5710 count = DebugGetLoadedScripts(NULL, 0);
5711
5712 // Allocate an array to hold the result.
5713 Handle<FixedArray> instances = Factory::NewFixedArray(count);
5714
5715 // Fill the script objects.
5716 count = DebugGetLoadedScripts(*instances, count);
5717
5718 // Convert the script objects to proper JS objects.
5719 for (int i = 0; i < count; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005720 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
5721 // Get the script wrapper in a local handle before calling GetScriptWrapper,
5722 // because using
5723 // instances->set(i, *GetScriptWrapper(script))
5724 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
5725 // already have deferenced the instances handle.
5726 Handle<JSValue> wrapper = GetScriptWrapper(script);
5727 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728 }
5729
5730 // Return result as a JS array.
5731 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
5732 Handle<JSArray>::cast(result)->SetContent(*instances);
5733 return *result;
5734}
5735
5736
5737// Helper function used by Runtime_DebugReferencedBy below.
5738static int DebugReferencedBy(JSObject* target,
5739 Object* instance_filter, int max_references,
5740 FixedArray* instances, int instances_size,
5741 JSFunction* context_extension_function,
5742 JSFunction* arguments_function) {
5743 NoHandleAllocation ha;
5744 AssertNoAllocation no_alloc;
5745
5746 // Iterate the heap.
5747 int count = 0;
5748 JSObject* last = NULL;
5749 HeapIterator iterator;
5750 while (iterator.has_next() &&
5751 (max_references == 0 || count < max_references)) {
5752 // Only look at all JSObjects.
5753 HeapObject* heap_obj = iterator.next();
5754 if (heap_obj->IsJSObject()) {
5755 // Skip context extension objects and argument arrays as these are
5756 // checked in the context of functions using them.
5757 JSObject* obj = JSObject::cast(heap_obj);
5758 if (obj->map()->constructor() == context_extension_function ||
5759 obj->map()->constructor() == arguments_function) {
5760 continue;
5761 }
5762
5763 // Check if the JS object has a reference to the object looked for.
5764 if (obj->ReferencesObject(target)) {
5765 // Check instance filter if supplied. This is normally used to avoid
5766 // references from mirror objects (see Runtime_IsInPrototypeChain).
5767 if (!instance_filter->IsUndefined()) {
5768 Object* V = obj;
5769 while (true) {
5770 Object* prototype = V->GetPrototype();
5771 if (prototype->IsNull()) {
5772 break;
5773 }
5774 if (instance_filter == prototype) {
5775 obj = NULL; // Don't add this object.
5776 break;
5777 }
5778 V = prototype;
5779 }
5780 }
5781
5782 if (obj != NULL) {
5783 // Valid reference found add to instance array if supplied an update
5784 // count.
5785 if (instances != NULL && count < instances_size) {
5786 instances->set(count, obj);
5787 }
5788 last = obj;
5789 count++;
5790 }
5791 }
5792 }
5793 }
5794
5795 // Check for circular reference only. This can happen when the object is only
5796 // referenced from mirrors and has a circular reference in which case the
5797 // object is not really alive and would have been garbage collected if not
5798 // referenced from the mirror.
5799 if (count == 1 && last == target) {
5800 count = 0;
5801 }
5802
5803 // Return the number of referencing objects found.
5804 return count;
5805}
5806
5807
5808// Scan the heap for objects with direct references to an object
5809// args[0]: the object to find references to
5810// args[1]: constructor function for instances to exclude (Mirror)
5811// args[2]: the the maximum number of objects to return
5812static Object* Runtime_DebugReferencedBy(Arguments args) {
5813 ASSERT(args.length() == 3);
5814
5815 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005816 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005817
5818 // Check parameters.
5819 CONVERT_CHECKED(JSObject, target, args[0]);
5820 Object* instance_filter = args[1];
5821 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
5822 instance_filter->IsJSObject());
5823 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
5824 RUNTIME_ASSERT(max_references >= 0);
5825
5826 // Get the constructor function for context extension and arguments array.
5827 JSFunction* context_extension_function =
5828 Top::context()->global_context()->context_extension_function();
5829 JSObject* arguments_boilerplate =
5830 Top::context()->global_context()->arguments_boilerplate();
5831 JSFunction* arguments_function =
5832 JSFunction::cast(arguments_boilerplate->map()->constructor());
5833
5834 // Get the number of referencing objects.
5835 int count;
5836 count = DebugReferencedBy(target, instance_filter, max_references,
5837 NULL, 0,
5838 context_extension_function, arguments_function);
5839
5840 // Allocate an array to hold the result.
5841 Object* object = Heap::AllocateFixedArray(count);
5842 if (object->IsFailure()) return object;
5843 FixedArray* instances = FixedArray::cast(object);
5844
5845 // Fill the referencing objects.
5846 count = DebugReferencedBy(target, instance_filter, max_references,
5847 instances, count,
5848 context_extension_function, arguments_function);
5849
5850 // Return result as JS array.
5851 Object* result =
5852 Heap::AllocateJSObject(
5853 Top::context()->global_context()->array_function());
5854 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5855 return result;
5856}
5857
5858
5859// Helper function used by Runtime_DebugConstructedBy below.
5860static int DebugConstructedBy(JSFunction* constructor, int max_references,
5861 FixedArray* instances, int instances_size) {
5862 AssertNoAllocation no_alloc;
5863
5864 // Iterate the heap.
5865 int count = 0;
5866 HeapIterator iterator;
5867 while (iterator.has_next() &&
5868 (max_references == 0 || count < max_references)) {
5869 // Only look at all JSObjects.
5870 HeapObject* heap_obj = iterator.next();
5871 if (heap_obj->IsJSObject()) {
5872 JSObject* obj = JSObject::cast(heap_obj);
5873 if (obj->map()->constructor() == constructor) {
5874 // Valid reference found add to instance array if supplied an update
5875 // count.
5876 if (instances != NULL && count < instances_size) {
5877 instances->set(count, obj);
5878 }
5879 count++;
5880 }
5881 }
5882 }
5883
5884 // Return the number of referencing objects found.
5885 return count;
5886}
5887
5888
5889// Scan the heap for objects constructed by a specific function.
5890// args[0]: the constructor to find instances of
5891// args[1]: the the maximum number of objects to return
5892static Object* Runtime_DebugConstructedBy(Arguments args) {
5893 ASSERT(args.length() == 2);
5894
5895 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005896 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897
5898 // Check parameters.
5899 CONVERT_CHECKED(JSFunction, constructor, args[0]);
5900 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
5901 RUNTIME_ASSERT(max_references >= 0);
5902
5903 // Get the number of referencing objects.
5904 int count;
5905 count = DebugConstructedBy(constructor, max_references, NULL, 0);
5906
5907 // Allocate an array to hold the result.
5908 Object* object = Heap::AllocateFixedArray(count);
5909 if (object->IsFailure()) return object;
5910 FixedArray* instances = FixedArray::cast(object);
5911
5912 // Fill the referencing objects.
5913 count = DebugConstructedBy(constructor, max_references, instances, count);
5914
5915 // Return result as JS array.
5916 Object* result =
5917 Heap::AllocateJSObject(
5918 Top::context()->global_context()->array_function());
5919 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5920 return result;
5921}
5922
5923
ager@chromium.orgddb913d2009-01-27 10:01:48 +00005924// Find the effective prototype object as returned by __proto__.
5925// args[0]: the object to find the prototype for.
5926static Object* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927 ASSERT(args.length() == 1);
5928
5929 CONVERT_CHECKED(JSObject, obj, args[0]);
5930
ager@chromium.orgddb913d2009-01-27 10:01:48 +00005931 // Use the __proto__ accessor.
5932 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005933}
5934
5935
5936static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005937 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938 CPU::DebugBreak();
5939 return Heap::undefined_value();
5940}
5941
5942
5943// Finds the script object from the script data. NOTE: This operation uses
5944// heap traversal to find the function generated for the source position
5945// for the requested break point. For lazily compiled functions several heap
5946// traversals might be required rendering this operation as a rather slow
5947// operation. However for setting break points which is normally done through
5948// some kind of user interaction the performance is not crucial.
5949static Handle<Object> Runtime_GetScriptFromScriptName(
5950 Handle<String> script_name) {
5951 // Scan the heap for Script objects to find the script with the requested
5952 // script data.
5953 Handle<Script> script;
5954 HeapIterator iterator;
5955 while (script.is_null() && iterator.has_next()) {
5956 HeapObject* obj = iterator.next();
5957 // If a script is found check if it has the script data requested.
5958 if (obj->IsScript()) {
5959 if (Script::cast(obj)->name()->IsString()) {
5960 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
5961 script = Handle<Script>(Script::cast(obj));
5962 }
5963 }
5964 }
5965 }
5966
5967 // If no script with the requested script data is found return undefined.
5968 if (script.is_null()) return Factory::undefined_value();
5969
5970 // Return the script found.
5971 return GetScriptWrapper(script);
5972}
5973
5974
5975// Get the script object from script data. NOTE: Regarding performance
5976// see the NOTE for GetScriptFromScriptData.
5977// args[0]: script data for the script to find the source for
5978static Object* Runtime_GetScript(Arguments args) {
5979 HandleScope scope;
5980
5981 ASSERT(args.length() == 1);
5982
5983 CONVERT_CHECKED(String, script_name, args[0]);
5984
5985 // Find the requested script.
5986 Handle<Object> result =
5987 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
5988 return *result;
5989}
5990
5991
5992static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
5993#ifdef DEBUG
5994 HandleScope scope;
5995 ASSERT(args.length() == 1);
5996 // Get the function and make sure it is compiled.
5997 CONVERT_ARG_CHECKED(JSFunction, func, 0);
5998 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
5999 return Failure::Exception();
6000 }
6001 func->code()->PrintLn();
6002#endif // DEBUG
6003 return Heap::undefined_value();
6004}
6005
6006
6007static Object* Runtime_Abort(Arguments args) {
6008 ASSERT(args.length() == 2);
6009 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
6010 Smi::cast(args[1])->value());
6011 Top::PrintStack();
6012 OS::Abort();
6013 UNREACHABLE();
6014 return NULL;
6015}
6016
6017
kasper.lund44510672008-07-25 07:37:58 +00006018#ifdef DEBUG
6019// ListNatives is ONLY used by the fuzz-natives.js in debug mode
6020// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00006022 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 HandleScope scope;
6024 Handle<JSArray> result = Factory::NewJSArray(0);
6025 int index = 0;
6026#define ADD_ENTRY(Name, argc) \
6027 { \
6028 HandleScope inner; \
6029 Handle<String> name = \
6030 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
6031 Handle<JSArray> pair = Factory::NewJSArray(0); \
6032 SetElement(pair, 0, name); \
6033 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
6034 SetElement(result, index++, pair); \
6035 }
6036 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
6037#undef ADD_ENTRY
6038 return *result;
6039}
kasper.lund44510672008-07-25 07:37:58 +00006040#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006041
6042
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006043static Object* Runtime_Log(Arguments args) {
6044 ASSERT(args.length() == 2);
6045 String* format = String::cast(args[0]);
6046 Vector<const char> chars = format->ToAsciiVector();
6047 JSArray* elms = JSArray::cast(args[1]);
6048 Logger::LogRuntime(chars, elms);
6049 return Heap::undefined_value();
6050}
6051
6052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053static Object* Runtime_IS_VAR(Arguments args) {
6054 UNREACHABLE(); // implemented as macro in the parser
6055 return NULL;
6056}
6057
6058
6059// ----------------------------------------------------------------------------
6060// Implementation of Runtime
6061
6062#define F(name, nargs) \
6063 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
6064 static_cast<int>(Runtime::k##name) },
6065
6066static Runtime::Function Runtime_functions[] = {
6067 RUNTIME_FUNCTION_LIST(F)
6068 { NULL, NULL, NULL, 0, -1 }
6069};
6070
6071#undef F
6072
6073
6074Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
6075 ASSERT(0 <= fid && fid < kNofFunctions);
6076 return &Runtime_functions[fid];
6077}
6078
6079
6080Runtime::Function* Runtime::FunctionForName(const char* name) {
6081 for (Function* f = Runtime_functions; f->name != NULL; f++) {
6082 if (strcmp(f->name, name) == 0) {
6083 return f;
6084 }
6085 }
6086 return NULL;
6087}
6088
6089
6090void Runtime::PerformGC(Object* result) {
6091 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006092 if (failure->IsRetryAfterGC()) {
6093 // Try to do a garbage collection; ignore it if it fails. The C
6094 // entry stub will throw an out-of-memory exception in that case.
6095 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
6096 } else {
6097 // Handle last resort GC and make sure to allow future allocations
6098 // to grow the heap without causing GCs (if possible).
6099 Counters::gc_last_resort_from_js.Increment();
6100 Heap::CollectAllGarbage();
6101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006102}
6103
6104
6105} } // namespace v8::internal