blob: db2a104c37d7b772dd97f6c2d23503e97a4af09f [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000046#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000047#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000048#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000049#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000050#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000055#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000057#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000058#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000059#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
kasperl@chromium.org71affb52009-05-26 05:44:31 +000061namespace v8 {
62namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64
ager@chromium.org3e875802009-06-29 08:26:34 +000065#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067
68// Cast the given object to a value of the specified type and store
69// it in a variable with the given name. If the object is not of the
70// expected type call IllegalOperation and return.
71#define CONVERT_CHECKED(Type, name, obj) \
72 RUNTIME_ASSERT(obj->Is##Type()); \
73 Type* name = Type::cast(obj);
74
75#define CONVERT_ARG_CHECKED(Type, name, index) \
76 RUNTIME_ASSERT(args[index]->Is##Type()); \
77 Handle<Type> name = args.at<Type>(index);
78
kasper.lundbd3ec4e2008-07-09 11:06:54 +000079// Cast the given object to a boolean and store it in a variable with
80// the given name. If the object is not a boolean call IllegalOperation
81// and return.
82#define CONVERT_BOOLEAN_CHECKED(name, obj) \
83 RUNTIME_ASSERT(obj->IsBoolean()); \
84 bool name = (obj)->IsTrue();
85
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000086// Cast the given argument to a Smi and store its value in an int variable
87// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000088// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000089#define CONVERT_SMI_ARG_CHECKED(name, index) \
90 RUNTIME_ASSERT(args[index]->IsSmi()); \
91 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000093// Cast the given argument to a double and store it in a variable with
94// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000096#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
97 RUNTIME_ASSERT(args[index]->IsNumber()); \
98 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099
100// Call the specified converter on the object *comand store the result in
101// a variable of the specified type with the given name. If the
102// object is not a Number call IllegalOperation and return.
103#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
104 RUNTIME_ASSERT(obj->IsNumber()); \
105 type name = NumberTo##Type(obj);
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
109 JSObject* boilerplate) {
110 StackLimitCheck check(isolate);
111 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000116 if (!maybe_result->ToObject(&result)) return maybe_result;
117 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 JSObject* copy = JSObject::cast(result);
119
120 // Deep copy local properties.
121 if (copy->HasFastProperties()) {
122 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 for (int i = 0; i < properties->length(); i++) {
124 Object* value = properties->get(i);
125 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000128 if (!maybe_result->ToObject(&result)) return maybe_result;
129 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000130 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 }
132 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000133 int nof = copy->map()->inobject_properties();
134 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000135 Object* value = copy->InObjectPropertyAt(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
144 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 FixedArray* names = FixedArray::cast(result);
150 copy->GetLocalPropertyNames(names, 0);
151 for (int i = 0; i < names->length(); i++) {
152 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000156 // Only deep copy fields from the object literal expression.
157 // In particular, don't try to copy the length attribute of
158 // an array.
159 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160 Object* value =
161 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000164 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000165 if (!maybe_result->ToObject(&result)) return maybe_result;
166 }
167 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000168 // Creating object copy for literals. No strict mode needed.
169 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 }
175
176 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000178 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000179 switch (copy->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000180 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000181 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 if (elements->map() == heap->fixed_cow_array_map()) {
183 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000184#ifdef DEBUG
185 for (int i = 0; i < elements->length(); i++) {
186 ASSERT(!elements->get(i)->IsJSObject());
187 }
188#endif
189 } else {
190 for (int i = 0; i < elements->length(); i++) {
191 Object* value = elements->get(i);
192 if (value->IsJSObject()) {
193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
195 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000198 elements->set(i, result);
199 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000204 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000205 NumberDictionary* element_dictionary = copy->element_dictionary();
206 int capacity = element_dictionary->Capacity();
207 for (int i = 0; i < capacity; i++) {
208 Object* k = element_dictionary->KeyAt(i);
209 if (element_dictionary->IsKey(k)) {
210 Object* value = element_dictionary->ValueAt(i);
211 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000212 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
214 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000215 if (!maybe_result->ToObject(&result)) return maybe_result;
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 element_dictionary->ValueAtPut(i, result);
218 }
219 }
220 }
221 break;
222 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000223 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000224 UNIMPLEMENTED();
225 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000226 case EXTERNAL_PIXEL_ELEMENTS:
227 case EXTERNAL_BYTE_ELEMENTS:
228 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
229 case EXTERNAL_SHORT_ELEMENTS:
230 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
231 case EXTERNAL_INT_ELEMENTS:
232 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
233 case EXTERNAL_FLOAT_ELEMENTS:
234 case EXTERNAL_DOUBLE_ELEMENTS:
235 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000236 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
239 return copy;
240}
241
242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000243RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000244 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000246}
247
248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000249RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000251 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252}
253
254
ager@chromium.org236ad962008-09-25 09:45:57 +0000255static Handle<Map> ComputeObjectLiteralMap(
256 Handle<Context> context,
257 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000258 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000260 int properties_length = constant_properties->length();
261 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000262 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000263 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 for (int p = 0; p != properties_length; p += 2) {
266 Object* key = constant_properties->get(p);
267 uint32_t element_index = 0;
268 if (key->IsSymbol()) {
269 number_of_symbol_keys++;
270 } else if (key->ToArrayIndex(&element_index)) {
271 // An index key does not require space in the property backing store.
272 number_of_properties--;
273 } else {
274 // Bail out as a non-symbol non-index key makes caching impossible.
275 // ASSERT to make sure that the if condition after the loop is false.
276 ASSERT(number_of_symbol_keys != number_of_properties);
277 break;
278 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 // If we only have symbols and array indices among keys then we can
281 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 if ((number_of_symbol_keys == number_of_properties) &&
284 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 Handle<FixedArray> keys =
287 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000288 if (number_of_symbol_keys > 0) {
289 int index = 0;
290 for (int p = 0; p < properties_length; p += 2) {
291 Object* key = constant_properties->get(p);
292 if (key->IsSymbol()) {
293 keys->set(index++, key);
294 }
295 }
296 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
301 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000302 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000304 Handle<Map>(context->object_function()->initial_map()),
305 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000306}
307
308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000309static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000311 Handle<FixedArray> literals,
312 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314
315static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000317 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000318 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 bool should_have_fast_elements,
320 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 // Get the global context from the literals array. This is the
322 // context in which the function was created and we use the object
323 // function from this context to create the object literal. We do
324 // not use the object function from the current global context
325 // because this might be the object function from another context
326 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000327 Handle<Context> context =
328 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // In case we have function literals, we want the object to be in
331 // slow properties mode for now. We don't go in the map cache because
332 // maps with constant functions can't be shared if the functions are
333 // not the same (which is the common case).
334 bool is_result_from_cache = false;
335 Handle<Map> map = has_function_literal
336 ? Handle<Map>(context->object_function()->initial_map())
337 : ComputeObjectLiteralMap(context,
338 constant_properties,
339 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000342
343 // Normalize the elements of the boilerplate to save space if needed.
344 if (!should_have_fast_elements) NormalizeElements(boilerplate);
345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 // Add the constant properties to the boilerplate.
347 int length = constant_properties->length();
348 bool should_transform =
349 !is_result_from_cache && boilerplate->HasFastProperties();
350 if (should_transform || has_function_literal) {
351 // Normalize the properties of object to avoid n^2 behavior
352 // when extending the object multiple properties. Indicate the number of
353 // properties to be added.
354 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
355 }
356
357 for (int index = 0; index < length; index +=2) {
358 Handle<Object> key(constant_properties->get(index+0), isolate);
359 Handle<Object> value(constant_properties->get(index+1), isolate);
360 if (value->IsFixedArray()) {
361 // The value contains the constant_properties of a
362 // simple object or array literal.
363 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
364 value = CreateLiteralBoilerplate(isolate, literals, array);
365 if (value.is_null()) return value;
366 }
367 Handle<Object> result;
368 uint32_t element_index = 0;
369 if (key->IsSymbol()) {
370 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
371 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000372 result = SetOwnElement(boilerplate,
373 element_index,
374 value,
375 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 Handle<String> name(String::cast(*key));
378 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000379 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
380 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 } else if (key->ToArrayIndex(&element_index)) {
383 // Array index (uint32).
384 result = SetOwnElement(boilerplate,
385 element_index,
386 value,
387 kNonStrictMode);
388 } else {
389 // Non-uint32 number.
390 ASSERT(key->IsNumber());
391 double num = key->Number();
392 char arr[100];
393 Vector<char> buffer(arr, ARRAY_SIZE(arr));
394 const char* str = DoubleToCString(num, buffer);
395 Handle<String> name =
396 isolate->factory()->NewStringFromAscii(CStrVector(str));
397 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
398 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 // If setting the property on the boilerplate throws an
401 // exception, the exception is converted to an empty handle in
402 // the handle based operations. In that case, we need to
403 // convert back to an exception.
404 if (result.is_null()) return result;
405 }
406
407 // Transform to fast properties if necessary. For object literals with
408 // containing function literals we defer this operation until after all
409 // computed properties have been assigned so that we can generate
410 // constant function properties.
411 if (should_transform && !has_function_literal) {
412 TransformToFastProperties(boilerplate,
413 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
415
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000416 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000417}
418
419
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000422 Handle<FixedArray> literals,
423 Handle<FixedArray> elements) {
424 // Create the JSArray.
425 Handle<JSFunction> constructor(
426 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 const bool is_cow =
430 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433
434 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (is_cow) {
436#ifdef DEBUG
437 // Copy-on-write arrays must be shallow (and simple).
438 for (int i = 0; i < content->length(); i++) {
439 ASSERT(!content->get(i)->IsFixedArray());
440 }
441#endif
442 } else {
443 for (int i = 0; i < content->length(); i++) {
444 if (content->get(i)->IsFixedArray()) {
445 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000447 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
448 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000450 if (result.is_null()) return result;
451 content->set(i, *result);
452 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 }
454 }
455
456 // Set the elements.
457 Handle<JSArray>::cast(object)->SetContent(*content);
458 return object;
459}
460
461
462static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000464 Handle<FixedArray> literals,
465 Handle<FixedArray> array) {
466 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000469 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 return CreateObjectLiteralBoilerplate(isolate,
471 literals,
472 elements,
473 true,
474 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000475 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 return CreateObjectLiteralBoilerplate(isolate,
477 literals,
478 elements,
479 false,
480 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 default:
484 UNREACHABLE();
485 return Handle<Object>::null();
486 }
487}
488
489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000490RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000491 // Takes a FixedArray of elements containing the literal elements of
492 // the array literal and produces JSArray with those elements.
493 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000494 // which contains the context from which to get the Array function
495 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000496 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000497 ASSERT(args.length() == 3);
498 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000499 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000500 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 Handle<Object> object =
503 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000504 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000506 // Update the functions literal and return the boilerplate.
507 literals->set(literals_index, *object);
508 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000512RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000516 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000518 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
520 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521
522 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 Handle<Object> boilerplate(literals->get(literals_index), isolate);
524 if (*boilerplate == isolate->heap()->undefined_value()) {
525 boilerplate = CreateObjectLiteralBoilerplate(isolate,
526 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 should_have_fast_elements,
529 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 if (boilerplate.is_null()) return Failure::Exception();
531 // Update the functions literal and return the boilerplate.
532 literals->set(literals_index, *boilerplate);
533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000535}
536
537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000538RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000542 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000544 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
546 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547
548 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 Handle<Object> boilerplate(literals->get(literals_index), isolate);
550 if (*boilerplate == isolate->heap()->undefined_value()) {
551 boilerplate = CreateObjectLiteralBoilerplate(isolate,
552 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000553 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 should_have_fast_elements,
555 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 if (boilerplate.is_null()) return Failure::Exception();
557 // Update the functions literal and return the boilerplate.
558 literals->set(literals_index, *boilerplate);
559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561}
562
563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000564RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566 ASSERT(args.length() == 3);
567 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000568 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
570
571 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Handle<Object> boilerplate(literals->get(literals_index), isolate);
573 if (*boilerplate == isolate->heap()->undefined_value()) {
574 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 if (boilerplate.is_null()) return Failure::Exception();
576 // Update the functions literal and return the boilerplate.
577 literals->set(literals_index, *boilerplate);
578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580}
581
582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000583RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 ASSERT(args.length() == 3);
586 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000587 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
589
590 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 Handle<Object> boilerplate(literals->get(literals_index), isolate);
592 if (*boilerplate == isolate->heap()->undefined_value()) {
593 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594 if (boilerplate.is_null()) return Failure::Exception();
595 // Update the functions literal and return the boilerplate.
596 literals->set(literals_index, *boilerplate);
597 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000598 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000600 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603}
604
605
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000606RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
607 ASSERT(args.length() == 2);
608 Object* handler = args[0];
609 Object* prototype = args[1];
610 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000611 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000612 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
613}
614
615
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000616RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
617 ASSERT(args.length() == 1);
618 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000619 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000620}
621
622
623RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
624 ASSERT(args.length() == 1);
625 CONVERT_CHECKED(JSProxy, proxy, args[0]);
626 return proxy->handler();
627}
628
629
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000630RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
631 ASSERT(args.length() == 1);
632 CONVERT_CHECKED(JSProxy, proxy, args[0]);
633 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000634 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000635}
636
637
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
639 HandleScope scope(isolate);
640 ASSERT(args.length() == 1);
641 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
642 ASSERT(weakmap->map()->inobject_properties() == 0);
643 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
644 weakmap->set_table(*table);
645 weakmap->set_next(Smi::FromInt(0));
646 return *weakmap;
647}
648
649
650RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
651 NoHandleAllocation ha;
652 ASSERT(args.length() == 2);
653 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
654 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
655 // because they cannot be cast to JSObject to get an identity hash code.
656 CONVERT_ARG_CHECKED(JSObject, key, 1);
657 return weakmap->table()->Lookup(*key);
658}
659
660
661RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
662 HandleScope scope(isolate);
663 ASSERT(args.length() == 3);
664 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
665 // TODO(mstarzinger): See Runtime_WeakMapGet above.
666 CONVERT_ARG_CHECKED(JSObject, key, 1);
667 Handle<Object> value(args[2]);
668 Handle<ObjectHashTable> table(weakmap->table());
669 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
670 weakmap->set_table(*new_table);
671 return *value;
672}
673
674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000675RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676 NoHandleAllocation ha;
677 ASSERT(args.length() == 1);
678 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000679 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 return JSObject::cast(obj)->class_name();
681}
682
ager@chromium.org7c537e22008-10-16 08:43:32 +0000683
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000684RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
685 NoHandleAllocation ha;
686 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000687 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
688 Object* obj = input_obj;
689 // We don't expect access checks to be needed on JSProxy objects.
690 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000691 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000692 if (obj->IsAccessCheckNeeded() &&
693 !isolate->MayNamedAccess(JSObject::cast(obj),
694 isolate->heap()->Proto_symbol(),
695 v8::ACCESS_GET)) {
696 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
697 return isolate->heap()->undefined_value();
698 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000699 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000700 } while (obj->IsJSObject() &&
701 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000702 return obj;
703}
704
705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000706RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707 NoHandleAllocation ha;
708 ASSERT(args.length() == 2);
709 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
710 Object* O = args[0];
711 Object* V = args[1];
712 while (true) {
713 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 if (prototype->IsNull()) return isolate->heap()->false_value();
715 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716 V = prototype;
717 }
718}
719
720
ager@chromium.org9085a012009-05-11 19:22:57 +0000721// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000723 NoHandleAllocation ha;
724 ASSERT(args.length() == 2);
725 CONVERT_CHECKED(JSObject, jsobject, args[0]);
726 CONVERT_CHECKED(JSObject, proto, args[1]);
727
728 // Sanity checks. The old prototype (that we are replacing) could
729 // theoretically be null, but if it is not null then check that we
730 // didn't already install a hidden prototype here.
731 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
732 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
733 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
734
735 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000736 Object* map_or_failure;
737 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
738 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
739 return maybe_map_or_failure;
740 }
741 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000742 Map* new_proto_map = Map::cast(map_or_failure);
743
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
745 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
746 return maybe_map_or_failure;
747 }
748 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000749 Map* new_map = Map::cast(map_or_failure);
750
751 // Set proto's prototype to be the old prototype of the object.
752 new_proto_map->set_prototype(jsobject->GetPrototype());
753 proto->set_map(new_proto_map);
754 new_proto_map->set_is_hidden_prototype();
755
756 // Set the object's prototype to proto.
757 new_map->set_prototype(proto);
758 jsobject->set_map(new_map);
759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000760 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000761}
762
763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000764RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000766 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000767 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000768 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769}
770
771
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000772// Recursively traverses hidden prototypes if property is not found
773static void GetOwnPropertyImplementation(JSObject* obj,
774 String* name,
775 LookupResult* result) {
776 obj->LocalLookupRealNamedProperty(name, result);
777
778 if (!result->IsProperty()) {
779 Object* proto = obj->GetPrototype();
780 if (proto->IsJSObject() &&
781 JSObject::cast(proto)->map()->is_hidden_prototype())
782 GetOwnPropertyImplementation(JSObject::cast(proto),
783 name, result);
784 }
785}
786
787
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000788static bool CheckAccessException(LookupResult* result,
789 v8::AccessType access_type) {
790 if (result->type() == CALLBACKS) {
791 Object* callback = result->GetCallbackObject();
792 if (callback->IsAccessorInfo()) {
793 AccessorInfo* info = AccessorInfo::cast(callback);
794 bool can_access =
795 (access_type == v8::ACCESS_HAS &&
796 (info->all_can_read() || info->all_can_write())) ||
797 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
798 (access_type == v8::ACCESS_SET && info->all_can_write());
799 return can_access;
800 }
801 }
802
803 return false;
804}
805
806
807static bool CheckAccess(JSObject* obj,
808 String* name,
809 LookupResult* result,
810 v8::AccessType access_type) {
811 ASSERT(result->IsProperty());
812
813 JSObject* holder = result->holder();
814 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000816 while (true) {
817 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000819 // Access check callback denied the access, but some properties
820 // can have a special permissions which override callbacks descision
821 // (currently see v8::AccessControl).
822 break;
823 }
824
825 if (current == holder) {
826 return true;
827 }
828
829 current = JSObject::cast(current->GetPrototype());
830 }
831
832 // API callbacks can have per callback access exceptions.
833 switch (result->type()) {
834 case CALLBACKS: {
835 if (CheckAccessException(result, access_type)) {
836 return true;
837 }
838 break;
839 }
840 case INTERCEPTOR: {
841 // If the object has an interceptor, try real named properties.
842 // Overwrite the result to fetch the correct property later.
843 holder->LookupRealNamedProperty(name, result);
844 if (result->IsProperty()) {
845 if (CheckAccessException(result, access_type)) {
846 return true;
847 }
848 }
849 break;
850 }
851 default:
852 break;
853 }
854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 return false;
857}
858
859
860// TODO(1095): we should traverse hidden prototype hierachy as well.
861static bool CheckElementAccess(JSObject* obj,
862 uint32_t index,
863 v8::AccessType access_type) {
864 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000866 return false;
867 }
868
869 return true;
870}
871
872
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000873// Enumerator used as indices into the array returned from GetOwnProperty
874enum PropertyDescriptorIndices {
875 IS_ACCESSOR_INDEX,
876 VALUE_INDEX,
877 GETTER_INDEX,
878 SETTER_INDEX,
879 WRITABLE_INDEX,
880 ENUMERABLE_INDEX,
881 CONFIGURABLE_INDEX,
882 DESCRIPTOR_SIZE
883};
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Returns an array with the property description:
886// if args[1] is not a property on args[0]
887// returns undefined
888// if args[1] is a data property on args[0]
889// [false, value, Writeable, Enumerable, Configurable]
890// if args[1] is an accessor on args[0]
891// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000892RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000893 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 Heap* heap = isolate->heap();
895 HandleScope scope(isolate);
896 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
897 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000898 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000899 CONVERT_ARG_CHECKED(JSObject, obj, 0);
900 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000902 // This could be an element.
903 uint32_t index;
904 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 switch (obj->HasLocalElement(index)) {
906 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000908
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 case JSObject::STRING_CHARACTER_ELEMENT: {
910 // Special handling of string objects according to ECMAScript 5
911 // 15.5.5.2. Note that this might be a string object with elements
912 // other than the actual string value. This is covered by the
913 // subsequent cases.
914 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
915 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000919 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(WRITABLE_INDEX, heap->false_value());
921 elms->set(ENUMERABLE_INDEX, heap->false_value());
922 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000923 return *desc;
924 }
925
926 case JSObject::INTERCEPTED_ELEMENT:
927 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000929 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000931 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 elms->set(WRITABLE_INDEX, heap->true_value());
933 elms->set(ENUMERABLE_INDEX, heap->true_value());
934 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000935 return *desc;
936 }
937
938 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000939 Handle<JSObject> holder = obj;
940 if (obj->IsJSGlobalProxy()) {
941 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943 ASSERT(proto->IsJSGlobalObject());
944 holder = Handle<JSObject>(JSObject::cast(proto));
945 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000946 FixedArray* elements = FixedArray::cast(holder->elements());
947 NumberDictionary* dictionary = NULL;
948 if (elements->map() == heap->non_strict_arguments_elements_map()) {
949 dictionary = NumberDictionary::cast(elements->get(1));
950 } else {
951 dictionary = NumberDictionary::cast(elements);
952 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000953 int entry = dictionary->FindEntry(index);
954 ASSERT(entry != NumberDictionary::kNotFound);
955 PropertyDetails details = dictionary->DetailsAt(entry);
956 switch (details.type()) {
957 case CALLBACKS: {
958 // This is an accessor property with getter and/or setter.
959 FixedArray* callbacks =
960 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000962 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
963 elms->set(GETTER_INDEX, callbacks->get(0));
964 }
965 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
966 elms->set(SETTER_INDEX, callbacks->get(1));
967 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000968 break;
969 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000970 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000971 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000973 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000974 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000975 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000977 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000978 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000979 default:
980 UNREACHABLE();
981 break;
982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
984 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000985 return *desc;
986 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987 }
988 }
989
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000990 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000991 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000992
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000993 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000995 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000996
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000997 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000999 }
1000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1002 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001003
1004 bool is_js_accessor = (result.type() == CALLBACKS) &&
1005 (result.GetCallbackObject()->IsFixedArray());
1006
1007 if (is_js_accessor) {
1008 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001010
1011 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1012 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1013 elms->set(GETTER_INDEX, structure->get(0));
1014 }
1015 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1016 elms->set(SETTER_INDEX, structure->get(1));
1017 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001018 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1020 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001021
1022 PropertyAttributes attrs;
1023 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001024 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001025 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1026 if (!maybe_value->ToObject(&value)) return maybe_value;
1027 }
1028 elms->set(VALUE_INDEX, value);
1029 }
1030
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001031 return *desc;
1032}
1033
1034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001035RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001036 ASSERT(args.length() == 1);
1037 CONVERT_CHECKED(JSObject, obj, args[0]);
1038 return obj->PreventExtensions();
1039}
1040
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001042RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001043 ASSERT(args.length() == 1);
1044 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 obj = JSObject::cast(proto);
1050 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001051 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001052}
1053
1054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001055RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001058 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1059 CONVERT_ARG_CHECKED(String, pattern, 1);
1060 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001061 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1062 if (result.is_null()) return Failure::Exception();
1063 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064}
1065
1066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001067RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001070 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072}
1073
1074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001075RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 ASSERT(args.length() == 1);
1077 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001078 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080}
1081
1082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001083RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 ASSERT(args.length() == 2);
1085 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001087 int index = field->value();
1088 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1089 InstanceType type = templ->map()->instance_type();
1090 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1091 type == OBJECT_TEMPLATE_INFO_TYPE);
1092 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001093 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001094 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1095 } else {
1096 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1097 }
1098 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
1101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001102RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001103 ASSERT(args.length() == 1);
1104 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001105 Map* old_map = object->map();
1106 bool needs_access_checks = old_map->is_access_check_needed();
1107 if (needs_access_checks) {
1108 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001109 Object* new_map;
1110 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1111 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1112 }
ager@chromium.org32912102009-01-16 10:38:43 +00001113
1114 Map::cast(new_map)->set_is_access_check_needed(false);
1115 object->set_map(Map::cast(new_map));
1116 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001117 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001118}
1119
1120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001121RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001122 ASSERT(args.length() == 1);
1123 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001124 Map* old_map = object->map();
1125 if (!old_map->is_access_check_needed()) {
1126 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001127 Object* new_map;
1128 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1129 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1130 }
ager@chromium.org32912102009-01-16 10:38:43 +00001131
1132 Map::cast(new_map)->set_is_access_check_needed(true);
1133 object->set_map(Map::cast(new_map));
1134 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001135 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001136}
1137
1138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001139static Failure* ThrowRedeclarationError(Isolate* isolate,
1140 const char* type,
1141 Handle<String> name) {
1142 HandleScope scope(isolate);
1143 Handle<Object> type_handle =
1144 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 Handle<Object> args[2] = { type_handle, name };
1146 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1148 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149}
1150
1151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001152RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001153 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001154 HandleScope scope(isolate);
1155 Handle<GlobalObject> global = Handle<GlobalObject>(
1156 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157
ager@chromium.org3811b432009-10-28 14:53:37 +00001158 Handle<Context> context = args.at<Context>(0);
1159 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001160 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162 // Traverse the name/value pairs and set the properties.
1163 int length = pairs->length();
1164 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168
1169 // We have to declare a global const property. To capture we only
1170 // assign to it when evaluating the assignment for "const x =
1171 // <expr>" the initial value is the hole.
1172 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001173 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 if (value->IsUndefined() || is_const_property) {
1175 // Lookup the property in the global object, and don't set the
1176 // value of the variable if the property is already there.
1177 LookupResult lookup;
1178 global->Lookup(*name, &lookup);
1179 if (lookup.IsProperty()) {
1180 // Determine if the property is local by comparing the holder
1181 // against the global object. The information will be used to
1182 // avoid throwing re-declaration errors when declaring
1183 // variables or constants that exist in the prototype chain.
1184 bool is_local = (*global == lookup.holder());
1185 // Get the property attributes and determine if the property is
1186 // read-only.
1187 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1188 bool is_read_only = (attributes & READ_ONLY) != 0;
1189 if (lookup.type() == INTERCEPTOR) {
1190 // If the interceptor says the property is there, we
1191 // just return undefined without overwriting the property.
1192 // Otherwise, we continue to setting the property.
1193 if (attributes != ABSENT) {
1194 // Check if the existing property conflicts with regards to const.
1195 if (is_local && (is_read_only || is_const_property)) {
1196 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001197 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 };
1199 // The property already exists without conflicting: Go to
1200 // the next declaration.
1201 continue;
1202 }
1203 // Fall-through and introduce the absent property by using
1204 // SetProperty.
1205 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001206 // For const properties, we treat a callback with this name
1207 // even in the prototype as a conflicting declaration.
1208 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001210 }
1211 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 if (is_local && (is_read_only || is_const_property)) {
1213 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001214 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216 // The property already exists without conflicting: Go to
1217 // the next declaration.
1218 continue;
1219 }
1220 }
1221 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001222 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001224 Handle<SharedFunctionInfo> shared =
1225 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001227 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1228 context,
1229 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 value = function;
1231 }
1232
1233 LookupResult lookup;
1234 global->LocalLookup(*name, &lookup);
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236 // There's a local property that we need to overwrite because
1237 // we're either declaring a function or there's an interceptor
1238 // that claims the property is absent.
1239 //
1240 // Check for conflicting re-declarations. We cannot have
1241 // conflicting types in case of intercepted properties because
1242 // they are absent.
1243 if (lookup.IsProperty() &&
1244 (lookup.type() != INTERCEPTOR) &&
1245 (lookup.IsReadOnly() || is_const_property)) {
1246 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001250 // Compute the property attributes. According to ECMA-262, section
1251 // 13, page 71, the property must be read-only and
1252 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1253 // property as read-only, so we don't either.
1254 int attr = NONE;
1255 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1256 attr |= DONT_DELETE;
1257 }
1258 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1259 if (is_const_property || (is_native && is_function_declaration)) {
1260 attr |= READ_ONLY;
1261 }
1262
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001263 // Safari does not allow the invocation of callback setters for
1264 // function declarations. To mimic this behavior, we do not allow
1265 // the invocation of setters for function values. This makes a
1266 // difference for global functions with the same names as event
1267 // handlers such as "function onload() {}". Firefox does call the
1268 // onload setter in those case and Safari does not. We follow
1269 // Safari for compatibility.
1270 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001271 // Do not change DONT_DELETE to false from true.
1272 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001274 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001275 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 RETURN_IF_EMPTY_HANDLE(isolate,
1278 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001279 name,
1280 value,
1281 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001283 StrictModeFlag strict_mode =
1284 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1285 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001286 RETURN_IF_EMPTY_HANDLE(isolate,
1287 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001288 name,
1289 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001290 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001291 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 }
1293 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001295 ASSERT(!isolate->has_pending_exception());
1296 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297}
1298
1299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001300RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001302 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303
ager@chromium.org7c537e22008-10-16 08:43:32 +00001304 CONVERT_ARG_CHECKED(Context, context, 0);
1305 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001306 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001307 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001308 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001310 // Declarations are always done in a function or global context.
1311 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
1313 int index;
1314 PropertyAttributes attributes;
1315 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001316 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001317 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001318 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 if (attributes != ABSENT) {
1321 // The name was declared before; check for conflicting
1322 // re-declarations: This is similar to the code in parser.cc in
1323 // the AstBuildingParser::Declare function.
1324 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1325 // Functions are not read-only.
1326 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1327 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001328 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 }
1330
1331 // Initialize it if necessary.
1332 if (*initial_value != NULL) {
1333 if (index >= 0) {
1334 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001335 // the function context or the arguments object.
1336 if (holder->IsContext()) {
1337 ASSERT(holder.is_identical_to(context));
1338 if (((attributes & READ_ONLY) == 0) ||
1339 context->get(index)->IsTheHole()) {
1340 context->set(index, *initial_value);
1341 }
1342 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001343 // The holder is an arguments object.
1344 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001345 Handle<Object> result = SetElement(arguments, index, initial_value,
1346 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001347 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 }
1349 } else {
1350 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001351 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001352 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001354 SetProperty(context_ext, name, initial_value,
1355 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001360 // The property is not in the function context. It needs to be
1361 // "declared" in the function context's extension context, or in the
1362 // global context.
1363 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001364 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001367 } else {
1368 // The function context's extension context does not exists - allocate
1369 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 context_ext = isolate->factory()->NewJSObject(
1371 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 // And store it in the extension slot.
1373 context->set_extension(*context_ext);
1374 }
1375 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 // Declare the property by setting it to the initial value if provided,
1378 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1379 // constant declarations).
1380 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001383 // Declaring a const context slot is a conflicting declaration if
1384 // there is a callback with that name in a prototype. It is
1385 // allowed to introduce const variables in
1386 // JSContextExtensionObjects. They are treated specially in
1387 // SetProperty and no setters are invoked for those since they are
1388 // not real JSObjects.
1389 if (initial_value->IsTheHole() &&
1390 !context_ext->IsJSContextExtensionObject()) {
1391 LookupResult lookup;
1392 context_ext->Lookup(*name, &lookup);
1393 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001395 }
1396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 RETURN_IF_EMPTY_HANDLE(isolate,
1398 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001399 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403}
1404
1405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001406RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408 // args[0] == name
1409 // args[1] == strict_mode
1410 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411
1412 // Determine if we need to assign to the variable if it already
1413 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1415 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416
1417 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001419 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001420 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422
1423 // According to ECMA-262, section 12.2, page 62, the property must
1424 // not be deletable.
1425 PropertyAttributes attributes = DONT_DELETE;
1426
1427 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001428 // there, there is a property with this name in the prototype chain.
1429 // We follow Safari and Firefox behavior and only set the property
1430 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001431 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001432 // Note that objects can have hidden prototypes, so we need to traverse
1433 // the whole chain of hidden prototypes to do a 'local' lookup.
1434 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001436 while (true) {
1437 real_holder->LocalLookup(*name, &lookup);
1438 if (lookup.IsProperty()) {
1439 // Determine if this is a redeclaration of something read-only.
1440 if (lookup.IsReadOnly()) {
1441 // If we found readonly property on one of hidden prototypes,
1442 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 if (real_holder != isolate->context()->global()) break;
1444 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001445 }
1446
1447 // Determine if this is a redeclaration of an intercepted read-only
1448 // property and figure out if the property exists at all.
1449 bool found = true;
1450 PropertyType type = lookup.type();
1451 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001453 Handle<JSObject> holder(real_holder);
1454 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1455 real_holder = *holder;
1456 if (intercepted == ABSENT) {
1457 // The interceptor claims the property isn't there. We need to
1458 // make sure to introduce it.
1459 found = false;
1460 } else if ((intercepted & READ_ONLY) != 0) {
1461 // The property is present, but read-only. Since we're trying to
1462 // overwrite it with a variable declaration we must throw a
1463 // re-declaration error. However if we found readonly property
1464 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 if (real_holder != isolate->context()->global()) break;
1466 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001467 }
1468 }
1469
1470 if (found && !assign) {
1471 // The global property is there and we're not assigning any value
1472 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001473 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001474 }
1475
1476 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 return real_holder->SetProperty(
1479 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001480 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001481
1482 Object* proto = real_holder->GetPrototype();
1483 if (!proto->IsJSObject())
1484 break;
1485
1486 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1487 break;
1488
1489 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 }
1491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001493 if (assign) {
1494 return global->SetProperty(*name, args[2], attributes, strict_mode);
1495 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 // All constants are declared with an initial value. The name
1502 // of the constant is the first argument and the initial value
1503 // is the second.
1504 RUNTIME_ASSERT(args.length() == 2);
1505 CONVERT_ARG_CHECKED(String, name, 0);
1506 Handle<Object> value = args.at<Object>(1);
1507
1508 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510
1511 // According to ECMA-262, section 12.2, page 62, the property must
1512 // not be deletable. Since it's a const, it must be READ_ONLY too.
1513 PropertyAttributes attributes =
1514 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1515
1516 // Lookup the property locally in the global object. If it isn't
1517 // there, we add the property and take special precautions to always
1518 // add it as a local property even in case of callbacks in the
1519 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001520 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 LookupResult lookup;
1522 global->LocalLookup(*name, &lookup);
1523 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001524 return global->SetLocalPropertyIgnoreAttributes(*name,
1525 *value,
1526 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
1528
1529 // Determine if this is a redeclaration of something not
1530 // read-only. In case the result is hidden behind an interceptor we
1531 // need to ask it for the property attributes.
1532 if (!lookup.IsReadOnly()) {
1533 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 }
1536
1537 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1538
1539 // Throw re-declaration error if the intercepted property is present
1540 // but not read-only.
1541 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 }
1544
1545 // Restore global object from context (in case of GC) and continue
1546 // with setting the value because the property is either absent or
1547 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001548 HandleScope handle_scope(isolate);
1549 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001551 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 // property through an interceptor and only do it if it's
1553 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001554 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001555 RETURN_IF_EMPTY_HANDLE(isolate,
1556 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001557 name,
1558 value,
1559 attributes,
1560 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 return *value;
1562 }
1563
1564 // Set the value, but only we're assigning the initial value to a
1565 // constant. For now, we determine this by checking if the
1566 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001567 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 PropertyType type = lookup.type();
1569 if (type == FIELD) {
1570 FixedArray* properties = global->properties();
1571 int index = lookup.GetFieldIndex();
1572 if (properties->get(index)->IsTheHole()) {
1573 properties->set(index, *value);
1574 }
1575 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001576 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1577 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 }
1579 } else {
1580 // Ignore re-initialization of constants that have already been
1581 // assigned a function value.
1582 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1583 }
1584
1585 // Use the set value as the result of the operation.
1586 return *value;
1587}
1588
1589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001590RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 ASSERT(args.length() == 3);
1593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 ASSERT(!value->IsTheHole());
1596 CONVERT_ARG_CHECKED(Context, context, 1);
1597 Handle<String> name(String::cast(args[2]));
1598
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001599 // Initializations are always done in a function or global context.
1600 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
1602 int index;
1603 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001604 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001605 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001606 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001607 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 // In most situations, the property introduced by the const
1610 // declaration should be present in the context extension object.
1611 // However, because declaration and initialization are separate, the
1612 // property might have been deleted (if it was introduced by eval)
1613 // before we reach the initialization point.
1614 //
1615 // Example:
1616 //
1617 // function f() { eval("delete x; const x;"); }
1618 //
1619 // In that case, the initialization behaves like a normal assignment
1620 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001623 // Property was found in a context. Perform the assignment if we
1624 // found some non-constant or an uninitialized constant.
1625 Handle<Context> context = Handle<Context>::cast(holder);
1626 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1627 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001628 }
1629 } else {
1630 // The holder is an arguments object.
1631 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001632 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001633 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001635 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 }
1637 return *value;
1638 }
1639
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 // The property could not be found, we introduce it in the global
1641 // context.
1642 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 Handle<JSObject> global = Handle<JSObject>(
1644 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001645 // Strict mode not needed (const disallowed in strict mode).
1646 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001647 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001648 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001649 return *value;
1650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001652 // The property was present in a context extension object.
1653 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 if (*context_ext == context->extension()) {
1656 // This is the property that was introduced by the const
1657 // declaration. Set it if it hasn't been set before. NOTE: We
1658 // cannot use GetProperty() to get the current value as it
1659 // 'unholes' the value.
1660 LookupResult lookup;
1661 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1662 ASSERT(lookup.IsProperty()); // the property was declared
1663 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1664
1665 PropertyType type = lookup.type();
1666 if (type == FIELD) {
1667 FixedArray* properties = context_ext->properties();
1668 int index = lookup.GetFieldIndex();
1669 if (properties->get(index)->IsTheHole()) {
1670 properties->set(index, *value);
1671 }
1672 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001673 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1674 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001675 }
1676 } else {
1677 // We should not reach here. Any real, named property should be
1678 // either a field or a dictionary slot.
1679 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
1681 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682 // The property was found in a different context extension object.
1683 // Set it if it is not a read-only property.
1684 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001685 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001686 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001688 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 return *value;
1693}
1694
1695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001696RUNTIME_FUNCTION(MaybeObject*,
1697 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001699 ASSERT(args.length() == 2);
1700 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001701 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001702 if (object->HasFastProperties()) {
1703 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1704 }
1705 return *object;
1706}
1707
1708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001709RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001711 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001712 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1713 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001716 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001717 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001718 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001719 RUNTIME_ASSERT(index >= 0);
1720 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001722 Handle<Object> result = RegExpImpl::Exec(regexp,
1723 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001726 if (result.is_null()) return Failure::Exception();
1727 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728}
1729
1730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001731RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001732 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001733 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001734 if (elements_count < 0 ||
1735 elements_count > FixedArray::kMaxLength ||
1736 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001738 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739 Object* new_object;
1740 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1743 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1746 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1748 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001749 {
1750 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001752 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 }
1755 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 array->set_elements(elements);
1758 array->set_length(Smi::FromInt(elements_count));
1759 // Write in-object properties after the length of the array.
1760 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1761 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1762 return array;
1763}
1764
1765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001766RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767 AssertNoAllocation no_alloc;
1768 ASSERT(args.length() == 5);
1769 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1770 CONVERT_CHECKED(String, source, args[1]);
1771
1772 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001774
1775 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001776 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777
1778 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780
1781 Map* map = regexp->map();
1782 Object* constructor = map->constructor();
1783 if (constructor->IsJSFunction() &&
1784 JSFunction::cast(constructor)->initial_map() == map) {
1785 // If we still have the original map, set in-object properties directly.
1786 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1787 // TODO(lrn): Consider skipping write barrier on booleans as well.
1788 // Both true and false should be in oldspace at all times.
1789 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1790 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1791 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1792 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1793 Smi::FromInt(0),
1794 SKIP_WRITE_BARRIER);
1795 return regexp;
1796 }
1797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799 PropertyAttributes final =
1800 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1801 PropertyAttributes writable =
1802 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001804 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001806 source,
1807 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001808 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001810 global,
1811 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 ASSERT(!result->IsFailure());
1813 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001815 ignoreCase,
1816 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 multiline,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
1822 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 Smi::FromInt(0),
1825 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 ASSERT(!result->IsFailure());
1827 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001828 return regexp;
1829}
1830
1831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001832RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001834 ASSERT(args.length() == 1);
1835 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1836 // This is necessary to enable fast checks for absence of elements
1837 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001839 return Smi::FromInt(0);
1840}
1841
1842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1844 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001845 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001846 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001847 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1848 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1849 Handle<JSFunction> optimized =
1850 isolate->factory()->NewFunction(key,
1851 JS_OBJECT_TYPE,
1852 JSObject::kHeaderSize,
1853 code,
1854 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001855 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001856 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001857 return optimized;
1858}
1859
1860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001861RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001863 ASSERT(args.length() == 1);
1864 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1865
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001866 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1867 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1868 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1869 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1870 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1871 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1872 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001873
1874 return *holder;
1875}
1876
1877
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1879 NoHandleAllocation handle_free;
1880 ASSERT(args.length() == 1);
1881 CONVERT_CHECKED(JSFunction, function, args[0]);
1882 SharedFunctionInfo* shared = function->shared();
1883 if (shared->native() || shared->strict_mode()) {
1884 return isolate->heap()->undefined_value();
1885 }
1886 // Returns undefined for strict or native functions, or
1887 // the associated global receiver for "normal" functions.
1888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001890 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001891 return global_context->global()->global_receiver();
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897 ASSERT(args.length() == 4);
1898 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001899 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 Handle<String> pattern = args.at<String>(2);
1901 Handle<String> flags = args.at<String>(3);
1902
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001903 // Get the RegExp function from the context in the literals array.
1904 // This is the RegExp function from the context in which the
1905 // function was created. We do not use the RegExp function from the
1906 // current global context because this might be the RegExp function
1907 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001908 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001909 Handle<JSFunction>(
1910 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 // Compute the regular expression literal.
1912 bool has_pending_exception;
1913 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001914 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1915 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001916 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 return Failure::Exception();
1919 }
1920 literals->set(index, *regexp);
1921 return *regexp;
1922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 1);
1928
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 return f->shared()->name();
1931}
1932
1933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001934RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001935 NoHandleAllocation ha;
1936 ASSERT(args.length() == 2);
1937
1938 CONVERT_CHECKED(JSFunction, f, args[0]);
1939 CONVERT_CHECKED(String, name, args[1]);
1940 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001941 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001942}
1943
1944
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001945RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1946 NoHandleAllocation ha;
1947 ASSERT(args.length() == 1);
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
1949 return isolate->heap()->ToBoolean(
1950 f->shared()->name_should_print_as_anonymous());
1951}
1952
1953
1954RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1955 NoHandleAllocation ha;
1956 ASSERT(args.length() == 1);
1957 CONVERT_CHECKED(JSFunction, f, args[0]);
1958 f->shared()->set_name_should_print_as_anonymous(true);
1959 return isolate->heap()->undefined_value();
1960}
1961
1962
whesse@chromium.org7b260152011-06-20 15:33:18 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1964 HandleScope scope(isolate);
1965 ASSERT(args.length() == 1);
1966
1967 CONVERT_CHECKED(JSFunction, fun, args[0]);
1968 fun->shared()->set_bound(true);
1969 return isolate->heap()->undefined_value();
1970}
1971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001972RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001973 NoHandleAllocation ha;
1974 ASSERT(args.length() == 1);
1975
1976 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001977 Object* obj = f->RemovePrototype();
1978 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001980 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001981}
1982
1983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001984RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 ASSERT(args.length() == 1);
1987
1988 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001989 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1990 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991
1992 return *GetScriptWrapper(Handle<Script>::cast(script));
1993}
1994
1995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001996RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 NoHandleAllocation ha;
1998 ASSERT(args.length() == 1);
1999
2000 CONVERT_CHECKED(JSFunction, f, args[0]);
2001 return f->shared()->GetSourceCode();
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006 NoHandleAllocation ha;
2007 ASSERT(args.length() == 1);
2008
2009 CONVERT_CHECKED(JSFunction, fun, args[0]);
2010 int pos = fun->shared()->start_position();
2011 return Smi::FromInt(pos);
2012}
2013
2014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002015RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002016 ASSERT(args.length() == 2);
2017
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002018 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002019 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2020
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002021 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2022
2023 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002024 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002025}
2026
2027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002028RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 NoHandleAllocation ha;
2030 ASSERT(args.length() == 2);
2031
2032 CONVERT_CHECKED(JSFunction, fun, args[0]);
2033 CONVERT_CHECKED(String, name, args[1]);
2034 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 NoHandleAllocation ha;
2041 ASSERT(args.length() == 2);
2042
2043 CONVERT_CHECKED(JSFunction, fun, args[0]);
2044 CONVERT_CHECKED(Smi, length, args[1]);
2045 fun->shared()->set_length(length->value());
2046 return length;
2047}
2048
2049
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002050// Creates a local, readonly, property called length with the correct
2051// length (when read by the user). This effectively overwrites the
2052// interceptor used to normally provide the length.
2053RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2054 NoHandleAllocation ha;
2055 ASSERT(args.length() == 2);
2056 CONVERT_CHECKED(JSFunction, fun, args[0]);
2057 CONVERT_CHECKED(Smi, length, args[1]);
2058 MaybeObject* maybe_name =
2059 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2060 String* name;
2061 if (!maybe_name->To(&name)) return maybe_name;
2062 PropertyAttributes attr =
2063 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2064 return fun->AddProperty(name, length, attr, kNonStrictMode);
2065}
2066
2067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002068RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002069 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 ASSERT(args.length() == 2);
2071
2072 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002073 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002074 Object* obj;
2075 { MaybeObject* maybe_obj =
2076 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2077 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002079 return args[0]; // return TOS
2080}
2081
2082
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002083RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2084 NoHandleAllocation ha;
2085 RUNTIME_ASSERT(args.length() == 1);
2086 CONVERT_CHECKED(JSFunction, function, args[0]);
2087
2088 MaybeObject* maybe_name =
2089 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2090 String* name;
2091 if (!maybe_name->To(&name)) return maybe_name;
2092
2093 if (function->HasFastProperties()) {
2094 // Construct a new field descriptor with updated attributes.
2095 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2096 int index = instance_desc->Search(name);
2097 ASSERT(index != DescriptorArray::kNotFound);
2098 PropertyDetails details(instance_desc->GetDetails(index));
2099 CallbacksDescriptor new_desc(name,
2100 instance_desc->GetValue(index),
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.index());
2103 // Construct a new field descriptors array containing the new descriptor.
2104 Object* descriptors_unchecked;
2105 { MaybeObject* maybe_descriptors_unchecked =
2106 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2107 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2108 return maybe_descriptors_unchecked;
2109 }
2110 }
2111 DescriptorArray* new_descriptors =
2112 DescriptorArray::cast(descriptors_unchecked);
2113 // Create a new map featuring the new field descriptors array.
2114 Object* map_unchecked;
2115 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2116 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2117 return maybe_map_unchecked;
2118 }
2119 }
2120 Map* new_map = Map::cast(map_unchecked);
2121 new_map->set_instance_descriptors(new_descriptors);
2122 function->set_map(new_map);
2123 } else { // Dictionary properties.
2124 // Directly manipulate the property details.
2125 int entry = function->property_dictionary()->FindEntry(name);
2126 ASSERT(entry != StringDictionary::kNotFound);
2127 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2128 PropertyDetails new_details(
2129 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2130 details.type(),
2131 details.index());
2132 function->property_dictionary()->DetailsAtPut(entry, new_details);
2133 }
2134 return function;
2135}
2136
2137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002138RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002139 NoHandleAllocation ha;
2140 ASSERT(args.length() == 1);
2141
2142 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002143 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002144}
2145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002147RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002148 NoHandleAllocation ha;
2149 ASSERT(args.length() == 1);
2150
2151 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002152 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002153}
2154
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002156RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002157 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 ASSERT(args.length() == 2);
2160
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002161 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 Handle<Object> code = args.at<Object>(1);
2163
2164 Handle<Context> context(target->context());
2165
2166 if (!code->IsNull()) {
2167 RUNTIME_ASSERT(code->IsJSFunction());
2168 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002169 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170
2171 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 return Failure::Exception();
2173 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002174 // Since we don't store the source for this we should never
2175 // optimize this.
2176 shared->code()->set_optimizable(false);
2177
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002178 // Set the code, scope info, formal parameter count,
2179 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002180 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002185 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002186 // Set the source code of the target function to undefined.
2187 // SetCode is only used for built-in constructors like String,
2188 // Array, and Object, and some web code
2189 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002190 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002191 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002192 // Clear the optimization hints related to the compiled code as these are no
2193 // longer valid when the code is overwritten.
2194 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 context = Handle<Context>(fun->context());
2196
2197 // Make sure we get a fresh copy of the literal vector to avoid
2198 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002199 int number_of_literals = fun->NumberOfLiterals();
2200 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 // Insert the object, regexp and array functions in the literals
2204 // array prefix. These are the functions that will be used when
2205 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002206 literals->set(JSFunction::kLiteralGlobalContextIndex,
2207 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 // It's okay to skip the write barrier here because the literals
2210 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002211 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213 }
2214
2215 target->set_context(*context);
2216 return *target;
2217}
2218
2219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002222 ASSERT(args.length() == 2);
2223 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002224 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002225 RUNTIME_ASSERT(num >= 0);
2226 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002228}
2229
2230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2232 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002234 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002236 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002237 }
2238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240}
2241
2242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002243RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002244 NoHandleAllocation ha;
2245 ASSERT(args.length() == 2);
2246
2247 CONVERT_CHECKED(String, subject, args[0]);
2248 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251 uint32_t i = 0;
2252 if (index->IsSmi()) {
2253 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002255 i = value;
2256 } else {
2257 ASSERT(index->IsHeapNumber());
2258 double value = HeapNumber::cast(index)->value();
2259 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002260 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002261
2262 // Flatten the string. If someone wants to get a char at an index
2263 // in a cons string, it is likely that more indices will be
2264 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002265 Object* flat;
2266 { MaybeObject* maybe_flat = subject->TryFlatten();
2267 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2268 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002269 subject = String::cast(flat);
2270
2271 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002273 }
2274
2275 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002276}
2277
2278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002279RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280 NoHandleAllocation ha;
2281 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283}
2284
lrn@chromium.org25156de2010-04-06 13:10:27 +00002285
2286class FixedArrayBuilder {
2287 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2289 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 length_(0) {
2291 // Require a non-zero initial size. Ensures that doubling the size to
2292 // extend the array will work.
2293 ASSERT(initial_capacity > 0);
2294 }
2295
2296 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2297 : array_(backing_store),
2298 length_(0) {
2299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
2326 ASSERT(length_ < capacity());
2327 array_->set(length_, value);
2328 length_++;
2329 }
2330
2331 void Add(Smi* value) {
2332 ASSERT(length_ < capacity());
2333 array_->set(length_, value);
2334 length_++;
2335 }
2336
2337 Handle<FixedArray> array() {
2338 return array_;
2339 }
2340
2341 int length() {
2342 return length_;
2343 }
2344
2345 int capacity() {
2346 return array_->length();
2347 }
2348
2349 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002350 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351 result_array->set_length(Smi::FromInt(length_));
2352 return result_array;
2353 }
2354
2355 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2356 target_array->set_elements(*array_);
2357 target_array->set_length(Smi::FromInt(length_));
2358 return target_array;
2359 }
2360
2361 private:
2362 Handle<FixedArray> array_;
2363 int length_;
2364};
2365
2366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368const int kStringBuilderConcatHelperLengthBits = 11;
2369const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002370
2371template <typename schar>
2372static inline void StringBuilderConcatHelper(String*,
2373 schar*,
2374 FixedArray*,
2375 int);
2376
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2378 StringBuilderSubstringLength;
2379typedef BitField<int,
2380 kStringBuilderConcatHelperLengthBits,
2381 kStringBuilderConcatHelperPositionBits>
2382 StringBuilderSubstringPosition;
2383
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384
2385class ReplacementStringBuilder {
2386 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002387 ReplacementStringBuilder(Heap* heap,
2388 Handle<String> subject,
2389 int estimated_part_count)
2390 : heap_(heap),
2391 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002394 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 // Require a non-zero initial size. Ensures that doubling the size to
2396 // extend the array will work.
2397 ASSERT(estimated_part_count > 0);
2398 }
2399
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2401 int from,
2402 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403 ASSERT(from >= 0);
2404 int length = to - from;
2405 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 if (StringBuilderSubstringLength::is_valid(length) &&
2407 StringBuilderSubstringPosition::is_valid(from)) {
2408 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2409 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002411 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002412 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 builder->Add(Smi::FromInt(-length));
2414 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 }
2417
2418
2419 void EnsureCapacity(int elements) {
2420 array_builder_.EnsureCapacity(elements);
2421 }
2422
2423
2424 void AddSubjectSlice(int from, int to) {
2425 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 }
2428
2429
2430 void AddString(Handle<String> string) {
2431 int length = string->length();
2432 ASSERT(length > 0);
2433 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002434 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 is_ascii_ = false;
2436 }
2437 IncrementCharacterCount(length);
2438 }
2439
2440
2441 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002442 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002443 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 }
2445
2446 Handle<String> joined_string;
2447 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 char* char_buffer = seq->GetChars();
2451 StringBuilderConcatHelper(*subject_,
2452 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 *array_builder_.array(),
2454 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002455 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 } else {
2457 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002458 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 uc16* char_buffer = seq->GetChars();
2461 StringBuilderConcatHelper(*subject_,
2462 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002463 *array_builder_.array(),
2464 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002465 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002466 }
2467 return joined_string;
2468 }
2469
2470
2471 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002472 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 V8::FatalProcessOutOfMemory("String.replace result too large.");
2474 }
2475 character_count_ += by;
2476 }
2477
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002479 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002480 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002483 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2484 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002485 }
2486
2487
ager@chromium.org04921a82011-06-27 13:21:41 +00002488 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2489 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490 }
2491
2492
2493 void AddElement(Object* element) {
2494 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 ASSERT(array_builder_.capacity() > array_builder_.length());
2496 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 }
2498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002499 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002500 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002502 int character_count_;
2503 bool is_ascii_;
2504};
2505
2506
2507class CompiledReplacement {
2508 public:
2509 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002510 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002511
2512 void Compile(Handle<String> replacement,
2513 int capture_count,
2514 int subject_length);
2515
2516 void Apply(ReplacementStringBuilder* builder,
2517 int match_from,
2518 int match_to,
2519 Handle<JSArray> last_match_info);
2520
2521 // Number of distinct parts of the replacement pattern.
2522 int parts() {
2523 return parts_.length();
2524 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002525
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002526 bool simple_hint() {
2527 return simple_hint_;
2528 }
2529
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002530 private:
2531 enum PartType {
2532 SUBJECT_PREFIX = 1,
2533 SUBJECT_SUFFIX,
2534 SUBJECT_CAPTURE,
2535 REPLACEMENT_SUBSTRING,
2536 REPLACEMENT_STRING,
2537
2538 NUMBER_OF_PART_TYPES
2539 };
2540
2541 struct ReplacementPart {
2542 static inline ReplacementPart SubjectMatch() {
2543 return ReplacementPart(SUBJECT_CAPTURE, 0);
2544 }
2545 static inline ReplacementPart SubjectCapture(int capture_index) {
2546 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2547 }
2548 static inline ReplacementPart SubjectPrefix() {
2549 return ReplacementPart(SUBJECT_PREFIX, 0);
2550 }
2551 static inline ReplacementPart SubjectSuffix(int subject_length) {
2552 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2553 }
2554 static inline ReplacementPart ReplacementString() {
2555 return ReplacementPart(REPLACEMENT_STRING, 0);
2556 }
2557 static inline ReplacementPart ReplacementSubString(int from, int to) {
2558 ASSERT(from >= 0);
2559 ASSERT(to > from);
2560 return ReplacementPart(-from, to);
2561 }
2562
2563 // If tag <= 0 then it is the negation of a start index of a substring of
2564 // the replacement pattern, otherwise it's a value from PartType.
2565 ReplacementPart(int tag, int data)
2566 : tag(tag), data(data) {
2567 // Must be non-positive or a PartType value.
2568 ASSERT(tag < NUMBER_OF_PART_TYPES);
2569 }
2570 // Either a value of PartType or a non-positive number that is
2571 // the negation of an index into the replacement string.
2572 int tag;
2573 // The data value's interpretation depends on the value of tag:
2574 // tag == SUBJECT_PREFIX ||
2575 // tag == SUBJECT_SUFFIX: data is unused.
2576 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2577 // tag == REPLACEMENT_SUBSTRING ||
2578 // tag == REPLACEMENT_STRING: data is index into array of substrings
2579 // of the replacement string.
2580 // tag <= 0: Temporary representation of the substring of the replacement
2581 // string ranging over -tag .. data.
2582 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2583 // substring objects.
2584 int data;
2585 };
2586
2587 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002588 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002589 Vector<Char> characters,
2590 int capture_count,
2591 int subject_length) {
2592 int length = characters.length();
2593 int last = 0;
2594 for (int i = 0; i < length; i++) {
2595 Char c = characters[i];
2596 if (c == '$') {
2597 int next_index = i + 1;
2598 if (next_index == length) { // No next character!
2599 break;
2600 }
2601 Char c2 = characters[next_index];
2602 switch (c2) {
2603 case '$':
2604 if (i > last) {
2605 // There is a substring before. Include the first "$".
2606 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2607 last = next_index + 1; // Continue after the second "$".
2608 } else {
2609 // Let the next substring start with the second "$".
2610 last = next_index;
2611 }
2612 i = next_index;
2613 break;
2614 case '`':
2615 if (i > last) {
2616 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2617 }
2618 parts->Add(ReplacementPart::SubjectPrefix());
2619 i = next_index;
2620 last = i + 1;
2621 break;
2622 case '\'':
2623 if (i > last) {
2624 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2625 }
2626 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2627 i = next_index;
2628 last = i + 1;
2629 break;
2630 case '&':
2631 if (i > last) {
2632 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2633 }
2634 parts->Add(ReplacementPart::SubjectMatch());
2635 i = next_index;
2636 last = i + 1;
2637 break;
2638 case '0':
2639 case '1':
2640 case '2':
2641 case '3':
2642 case '4':
2643 case '5':
2644 case '6':
2645 case '7':
2646 case '8':
2647 case '9': {
2648 int capture_ref = c2 - '0';
2649 if (capture_ref > capture_count) {
2650 i = next_index;
2651 continue;
2652 }
2653 int second_digit_index = next_index + 1;
2654 if (second_digit_index < length) {
2655 // Peek ahead to see if we have two digits.
2656 Char c3 = characters[second_digit_index];
2657 if ('0' <= c3 && c3 <= '9') { // Double digits.
2658 int double_digit_ref = capture_ref * 10 + c3 - '0';
2659 if (double_digit_ref <= capture_count) {
2660 next_index = second_digit_index;
2661 capture_ref = double_digit_ref;
2662 }
2663 }
2664 }
2665 if (capture_ref > 0) {
2666 if (i > last) {
2667 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2668 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002669 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2671 last = next_index + 1;
2672 }
2673 i = next_index;
2674 break;
2675 }
2676 default:
2677 i = next_index;
2678 break;
2679 }
2680 }
2681 }
2682 if (length > last) {
2683 if (last == 0) {
2684 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002685 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002686 } else {
2687 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2688 }
2689 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002690 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 }
2692
2693 ZoneList<ReplacementPart> parts_;
2694 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002695 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002696};
2697
2698
2699void CompiledReplacement::Compile(Handle<String> replacement,
2700 int capture_count,
2701 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002702 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002704 String::FlatContent content = replacement->GetFlatContent();
2705 ASSERT(content.IsFlat());
2706 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002707 simple_hint_ = ParseReplacementPattern(&parts_,
2708 content.ToAsciiVector(),
2709 capture_count,
2710 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002711 } else {
2712 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002713 simple_hint_ = ParseReplacementPattern(&parts_,
2714 content.ToUC16Vector(),
2715 capture_count,
2716 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002717 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002718 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002720 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002721 int substring_index = 0;
2722 for (int i = 0, n = parts_.length(); i < n; i++) {
2723 int tag = parts_[i].tag;
2724 if (tag <= 0) { // A replacement string slice.
2725 int from = -tag;
2726 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002727 replacement_substrings_.Add(
2728 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729 parts_[i].tag = REPLACEMENT_SUBSTRING;
2730 parts_[i].data = substring_index;
2731 substring_index++;
2732 } else if (tag == REPLACEMENT_STRING) {
2733 replacement_substrings_.Add(replacement);
2734 parts_[i].data = substring_index;
2735 substring_index++;
2736 }
2737 }
2738}
2739
2740
2741void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2742 int match_from,
2743 int match_to,
2744 Handle<JSArray> last_match_info) {
2745 for (int i = 0, n = parts_.length(); i < n; i++) {
2746 ReplacementPart part = parts_[i];
2747 switch (part.tag) {
2748 case SUBJECT_PREFIX:
2749 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2750 break;
2751 case SUBJECT_SUFFIX: {
2752 int subject_length = part.data;
2753 if (match_to < subject_length) {
2754 builder->AddSubjectSlice(match_to, subject_length);
2755 }
2756 break;
2757 }
2758 case SUBJECT_CAPTURE: {
2759 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002760 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002761 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2762 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2763 if (from >= 0 && to > from) {
2764 builder->AddSubjectSlice(from, to);
2765 }
2766 break;
2767 }
2768 case REPLACEMENT_SUBSTRING:
2769 case REPLACEMENT_STRING:
2770 builder->AddString(replacement_substrings_[part.data]);
2771 break;
2772 default:
2773 UNREACHABLE();
2774 }
2775 }
2776}
2777
2778
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002779void FindAsciiStringIndices(Vector<const char> subject,
2780 char pattern,
2781 ZoneList<int>* indices,
2782 unsigned int limit) {
2783 ASSERT(limit > 0);
2784 // Collect indices of pattern in subject using memchr.
2785 // Stop after finding at most limit values.
2786 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2787 const char* subject_end = subject_start + subject.length();
2788 const char* pos = subject_start;
2789 while (limit > 0) {
2790 pos = reinterpret_cast<const char*>(
2791 memchr(pos, pattern, subject_end - pos));
2792 if (pos == NULL) return;
2793 indices->Add(static_cast<int>(pos - subject_start));
2794 pos++;
2795 limit--;
2796 }
2797}
2798
2799
2800template <typename SubjectChar, typename PatternChar>
2801void FindStringIndices(Isolate* isolate,
2802 Vector<const SubjectChar> subject,
2803 Vector<const PatternChar> pattern,
2804 ZoneList<int>* indices,
2805 unsigned int limit) {
2806 ASSERT(limit > 0);
2807 // Collect indices of pattern in subject.
2808 // Stop after finding at most limit values.
2809 int pattern_length = pattern.length();
2810 int index = 0;
2811 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2812 while (limit > 0) {
2813 index = search.Search(subject, index);
2814 if (index < 0) return;
2815 indices->Add(index);
2816 index += pattern_length;
2817 limit--;
2818 }
2819}
2820
2821
2822void FindStringIndicesDispatch(Isolate* isolate,
2823 String* subject,
2824 String* pattern,
2825 ZoneList<int>* indices,
2826 unsigned int limit) {
2827 {
2828 AssertNoAllocation no_gc;
2829 String::FlatContent subject_content = subject->GetFlatContent();
2830 String::FlatContent pattern_content = pattern->GetFlatContent();
2831 ASSERT(subject_content.IsFlat());
2832 ASSERT(pattern_content.IsFlat());
2833 if (subject_content.IsAscii()) {
2834 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2835 if (pattern_content.IsAscii()) {
2836 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2837 if (pattern_vector.length() == 1) {
2838 FindAsciiStringIndices(subject_vector,
2839 pattern_vector[0],
2840 indices,
2841 limit);
2842 } else {
2843 FindStringIndices(isolate,
2844 subject_vector,
2845 pattern_vector,
2846 indices,
2847 limit);
2848 }
2849 } else {
2850 FindStringIndices(isolate,
2851 subject_vector,
2852 pattern_content.ToUC16Vector(),
2853 indices,
2854 limit);
2855 }
2856 } else {
2857 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
2858 if (pattern->IsAsciiRepresentation()) {
2859 FindStringIndices(isolate,
2860 subject_vector,
2861 pattern_content.ToAsciiVector(),
2862 indices,
2863 limit);
2864 } else {
2865 FindStringIndices(isolate,
2866 subject_vector,
2867 pattern_content.ToUC16Vector(),
2868 indices,
2869 limit);
2870 }
2871 }
2872 }
2873}
2874
2875
2876template<typename ResultSeqString>
2877MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2878 Isolate* isolate,
2879 Handle<String> subject,
2880 Handle<JSRegExp> pattern_regexp,
2881 Handle<String> replacement) {
2882 ASSERT(subject->IsFlat());
2883 ASSERT(replacement->IsFlat());
2884
2885 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2886 ZoneList<int> indices(8);
2887 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2888 String* pattern =
2889 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2890 int subject_len = subject->length();
2891 int pattern_len = pattern->length();
2892 int replacement_len = replacement->length();
2893
2894 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2895
2896 int matches = indices.length();
2897 if (matches == 0) return *subject;
2898
2899 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2900 int subject_pos = 0;
2901 int result_pos = 0;
2902
2903 Handle<ResultSeqString> result;
2904 if (ResultSeqString::kHasAsciiEncoding) {
2905 result = Handle<ResultSeqString>::cast(
2906 isolate->factory()->NewRawAsciiString(result_len));
2907 } else {
2908 result = Handle<ResultSeqString>::cast(
2909 isolate->factory()->NewRawTwoByteString(result_len));
2910 }
2911
2912 for (int i = 0; i < matches; i++) {
2913 // Copy non-matched subject content.
2914 if (subject_pos < indices.at(i)) {
2915 String::WriteToFlat(*subject,
2916 result->GetChars() + result_pos,
2917 subject_pos,
2918 indices.at(i));
2919 result_pos += indices.at(i) - subject_pos;
2920 }
2921
2922 // Replace match.
2923 if (replacement_len > 0) {
2924 String::WriteToFlat(*replacement,
2925 result->GetChars() + result_pos,
2926 0,
2927 replacement_len);
2928 result_pos += replacement_len;
2929 }
2930
2931 subject_pos = indices.at(i) + pattern_len;
2932 }
2933 // Add remaining subject content at the end.
2934 if (subject_pos < subject_len) {
2935 String::WriteToFlat(*subject,
2936 result->GetChars() + result_pos,
2937 subject_pos,
2938 subject_len);
2939 }
2940 return *result;
2941}
2942
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002943
lrn@chromium.org303ada72010-10-27 09:33:13 +00002944MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002945 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002946 String* subject,
2947 JSRegExp* regexp,
2948 String* replacement,
2949 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002950 ASSERT(subject->IsFlat());
2951 ASSERT(replacement->IsFlat());
2952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002953 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954
2955 int length = subject->length();
2956 Handle<String> subject_handle(subject);
2957 Handle<JSRegExp> regexp_handle(regexp);
2958 Handle<String> replacement_handle(replacement);
2959 Handle<JSArray> last_match_info_handle(last_match_info);
2960 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2961 subject_handle,
2962 0,
2963 last_match_info_handle);
2964 if (match.is_null()) {
2965 return Failure::Exception();
2966 }
2967 if (match->IsNull()) {
2968 return *subject_handle;
2969 }
2970
2971 int capture_count = regexp_handle->CaptureCount();
2972
2973 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002974 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002975 CompiledReplacement compiled_replacement;
2976 compiled_replacement.Compile(replacement_handle,
2977 capture_count,
2978 length);
2979
2980 bool is_global = regexp_handle->GetFlags().is_global();
2981
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002982 // Shortcut for simple non-regexp global replacements
2983 if (is_global &&
2984 regexp->TypeTag() == JSRegExp::ATOM &&
2985 compiled_replacement.simple_hint()) {
2986 if (subject_handle->HasOnlyAsciiChars() &&
2987 replacement_handle->HasOnlyAsciiChars()) {
2988 return StringReplaceStringWithString<SeqAsciiString>(
2989 isolate, subject_handle, regexp_handle, replacement_handle);
2990 } else {
2991 return StringReplaceStringWithString<SeqTwoByteString>(
2992 isolate, subject_handle, regexp_handle, replacement_handle);
2993 }
2994 }
2995
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002996 // Guessing the number of parts that the final result string is built
2997 // from. Global regexps can match any number of times, so we guess
2998 // conservatively.
2999 int expected_parts =
3000 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003001 ReplacementStringBuilder builder(isolate->heap(),
3002 subject_handle,
3003 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004
3005 // Index of end of last match.
3006 int prev = 0;
3007
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003008 // Number of parts added by compiled replacement plus preceeding
3009 // string and possibly suffix after last match. It is possible for
3010 // all components to use two elements when encoded as two smis.
3011 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003012 bool matched = true;
3013 do {
3014 ASSERT(last_match_info_handle->HasFastElements());
3015 // Increase the capacity of the builder before entering local handle-scope,
3016 // so its internal buffer can safely allocate a new handle if it grows.
3017 builder.EnsureCapacity(parts_added_per_loop);
3018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003019 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003020 int start, end;
3021 {
3022 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003023 FixedArray* match_info_array =
3024 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025
3026 ASSERT_EQ(capture_count * 2 + 2,
3027 RegExpImpl::GetLastCaptureCount(match_info_array));
3028 start = RegExpImpl::GetCapture(match_info_array, 0);
3029 end = RegExpImpl::GetCapture(match_info_array, 1);
3030 }
3031
3032 if (prev < start) {
3033 builder.AddSubjectSlice(prev, start);
3034 }
3035 compiled_replacement.Apply(&builder,
3036 start,
3037 end,
3038 last_match_info_handle);
3039 prev = end;
3040
3041 // Only continue checking for global regexps.
3042 if (!is_global) break;
3043
3044 // Continue from where the match ended, unless it was an empty match.
3045 int next = end;
3046 if (start == end) {
3047 next = end + 1;
3048 if (next > length) break;
3049 }
3050
3051 match = RegExpImpl::Exec(regexp_handle,
3052 subject_handle,
3053 next,
3054 last_match_info_handle);
3055 if (match.is_null()) {
3056 return Failure::Exception();
3057 }
3058 matched = !match->IsNull();
3059 } while (matched);
3060
3061 if (prev < length) {
3062 builder.AddSubjectSlice(prev, length);
3063 }
3064
3065 return *(builder.ToString());
3066}
3067
3068
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003069template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003070MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003071 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003072 String* subject,
3073 JSRegExp* regexp,
3074 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003075 ASSERT(subject->IsFlat());
3076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003077 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078
3079 Handle<String> subject_handle(subject);
3080 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003081
3082 // Shortcut for simple non-regexp global replacements
3083 if (regexp_handle->GetFlags().is_global() &&
3084 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3085 Handle<String> empty_string_handle(HEAP->empty_string());
3086 if (subject_handle->HasOnlyAsciiChars()) {
3087 return StringReplaceStringWithString<SeqAsciiString>(
3088 isolate, subject_handle, regexp_handle, empty_string_handle);
3089 } else {
3090 return StringReplaceStringWithString<SeqTwoByteString>(
3091 isolate, subject_handle, regexp_handle, empty_string_handle);
3092 }
3093 }
3094
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003095 Handle<JSArray> last_match_info_handle(last_match_info);
3096 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3097 subject_handle,
3098 0,
3099 last_match_info_handle);
3100 if (match.is_null()) return Failure::Exception();
3101 if (match->IsNull()) return *subject_handle;
3102
3103 ASSERT(last_match_info_handle->HasFastElements());
3104
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003105 int start, end;
3106 {
3107 AssertNoAllocation match_info_array_is_not_in_a_handle;
3108 FixedArray* match_info_array =
3109 FixedArray::cast(last_match_info_handle->elements());
3110
3111 start = RegExpImpl::GetCapture(match_info_array, 0);
3112 end = RegExpImpl::GetCapture(match_info_array, 1);
3113 }
3114
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003115 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003116 int new_length = length - (end - start);
3117 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003118 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003119 }
3120 Handle<ResultSeqString> answer;
3121 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 answer = Handle<ResultSeqString>::cast(
3123 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003124 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 answer = Handle<ResultSeqString>::cast(
3126 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003127 }
3128
3129 // If the regexp isn't global, only match once.
3130 if (!regexp_handle->GetFlags().is_global()) {
3131 if (start > 0) {
3132 String::WriteToFlat(*subject_handle,
3133 answer->GetChars(),
3134 0,
3135 start);
3136 }
3137 if (end < length) {
3138 String::WriteToFlat(*subject_handle,
3139 answer->GetChars() + start,
3140 end,
3141 length);
3142 }
3143 return *answer;
3144 }
3145
3146 int prev = 0; // Index of end of last match.
3147 int next = 0; // Start of next search (prev unless last match was empty).
3148 int position = 0;
3149
3150 do {
3151 if (prev < start) {
3152 // Add substring subject[prev;start] to answer string.
3153 String::WriteToFlat(*subject_handle,
3154 answer->GetChars() + position,
3155 prev,
3156 start);
3157 position += start - prev;
3158 }
3159 prev = end;
3160 next = end;
3161 // Continue from where the match ended, unless it was an empty match.
3162 if (start == end) {
3163 next++;
3164 if (next > length) break;
3165 }
3166 match = RegExpImpl::Exec(regexp_handle,
3167 subject_handle,
3168 next,
3169 last_match_info_handle);
3170 if (match.is_null()) return Failure::Exception();
3171 if (match->IsNull()) break;
3172
3173 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003174 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003175 {
3176 AssertNoAllocation match_info_array_is_not_in_a_handle;
3177 FixedArray* match_info_array =
3178 FixedArray::cast(last_match_info_handle->elements());
3179 start = RegExpImpl::GetCapture(match_info_array, 0);
3180 end = RegExpImpl::GetCapture(match_info_array, 1);
3181 }
3182 } while (true);
3183
3184 if (prev < length) {
3185 // Add substring subject[prev;length] to answer string.
3186 String::WriteToFlat(*subject_handle,
3187 answer->GetChars() + position,
3188 prev,
3189 length);
3190 position += length - prev;
3191 }
3192
3193 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003194 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003195 }
3196
3197 // Shorten string and fill
3198 int string_size = ResultSeqString::SizeFor(position);
3199 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3200 int delta = allocated_string_size - string_size;
3201
3202 answer->set_length(position);
3203 if (delta == 0) return *answer;
3204
3205 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003206 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003207
3208 return *answer;
3209}
3210
3211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003212RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003213 ASSERT(args.length() == 4);
3214
3215 CONVERT_CHECKED(String, subject, args[0]);
3216 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003217 Object* flat_subject;
3218 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3219 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3220 return maybe_flat_subject;
3221 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003222 }
3223 subject = String::cast(flat_subject);
3224 }
3225
3226 CONVERT_CHECKED(String, replacement, args[2]);
3227 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003228 Object* flat_replacement;
3229 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3230 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3231 return maybe_flat_replacement;
3232 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003233 }
3234 replacement = String::cast(flat_replacement);
3235 }
3236
3237 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3238 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3239
3240 ASSERT(last_match_info->HasFastElements());
3241
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003242 if (replacement->length() == 0) {
3243 if (subject->HasOnlyAsciiChars()) {
3244 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003246 } else {
3247 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003248 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003249 }
3250 }
3251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 return StringReplaceRegExpWithString(isolate,
3253 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003254 regexp,
3255 replacement,
3256 last_match_info);
3257}
3258
3259
ager@chromium.org7c537e22008-10-16 08:43:32 +00003260// Perform string match of pattern on subject, starting at start index.
3261// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003262// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003263int Runtime::StringMatch(Isolate* isolate,
3264 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003265 Handle<String> pat,
3266 int start_index) {
3267 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003268 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003269
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003270 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003271 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003272
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003273 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003274 if (start_index + pattern_length > subject_length) return -1;
3275
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003276 if (!sub->IsFlat()) FlattenString(sub);
3277 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003278
ager@chromium.org7c537e22008-10-16 08:43:32 +00003279 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003280 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003281 String::FlatContent seq_sub = sub->GetFlatContent();
3282 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003283
ager@chromium.org7c537e22008-10-16 08:43:32 +00003284 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003285 if (seq_pat.IsAscii()) {
3286 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3287 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003289 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 pat_vector,
3291 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003292 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003293 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003294 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003295 pat_vector,
3296 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003297 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003298 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3299 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003300 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003301 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003302 pat_vector,
3303 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003305 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003306 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 pat_vector,
3308 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003309}
3310
3311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003313 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003314 ASSERT(args.length() == 3);
3315
ager@chromium.org7c537e22008-10-16 08:43:32 +00003316 CONVERT_ARG_CHECKED(String, sub, 0);
3317 CONVERT_ARG_CHECKED(String, pat, 1);
3318
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003319 Object* index = args[2];
3320 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003321 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003322
ager@chromium.org870a0b62008-11-04 11:43:05 +00003323 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003324 int position =
3325 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003326 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003327}
3328
3329
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003330template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003331static int StringMatchBackwards(Vector<const schar> subject,
3332 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003333 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003334 int pattern_length = pattern.length();
3335 ASSERT(pattern_length >= 1);
3336 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003337
3338 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003339 for (int i = 0; i < pattern_length; i++) {
3340 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003341 if (c > String::kMaxAsciiCharCode) {
3342 return -1;
3343 }
3344 }
3345 }
3346
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003347 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003348 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003349 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003350 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003351 while (j < pattern_length) {
3352 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003353 break;
3354 }
3355 j++;
3356 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003357 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003358 return i;
3359 }
3360 }
3361 return -1;
3362}
3363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003364RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003365 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366 ASSERT(args.length() == 3);
3367
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003368 CONVERT_ARG_CHECKED(String, sub, 0);
3369 CONVERT_ARG_CHECKED(String, pat, 1);
3370
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003372 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003373 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003374
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003376 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003378 if (start_index + pat_length > sub_length) {
3379 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003382 if (pat_length == 0) {
3383 return Smi::FromInt(start_index);
3384 }
3385
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003386 if (!sub->IsFlat()) FlattenString(sub);
3387 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003388
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003389 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003390 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3391
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003392 String::FlatContent sub_content = sub->GetFlatContent();
3393 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003394
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 if (pat_content.IsAscii()) {
3396 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3397 if (sub_content.IsAscii()) {
3398 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003399 pat_vector,
3400 start_index);
3401 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003402 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003403 pat_vector,
3404 start_index);
3405 }
3406 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003407 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3408 if (sub_content.IsAscii()) {
3409 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410 pat_vector,
3411 start_index);
3412 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003413 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003414 pat_vector,
3415 start_index);
3416 }
3417 }
3418
3419 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420}
3421
3422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003423RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 NoHandleAllocation ha;
3425 ASSERT(args.length() == 2);
3426
3427 CONVERT_CHECKED(String, str1, args[0]);
3428 CONVERT_CHECKED(String, str2, args[1]);
3429
3430 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003431 int str1_length = str1->length();
3432 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
3434 // Decide trivial cases without flattening.
3435 if (str1_length == 0) {
3436 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3437 return Smi::FromInt(-str2_length);
3438 } else {
3439 if (str2_length == 0) return Smi::FromInt(str1_length);
3440 }
3441
3442 int end = str1_length < str2_length ? str1_length : str2_length;
3443
3444 // No need to flatten if we are going to find the answer on the first
3445 // character. At this point we know there is at least one character
3446 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003447 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 if (d != 0) return Smi::FromInt(d);
3449
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003450 str1->TryFlatten();
3451 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003453 StringInputBuffer& buf1 =
3454 *isolate->runtime_state()->string_locale_compare_buf1();
3455 StringInputBuffer& buf2 =
3456 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457
3458 buf1.Reset(str1);
3459 buf2.Reset(str2);
3460
3461 for (int i = 0; i < end; i++) {
3462 uint16_t char1 = buf1.GetNext();
3463 uint16_t char2 = buf2.GetNext();
3464 if (char1 != char2) return Smi::FromInt(char1 - char2);
3465 }
3466
3467 return Smi::FromInt(str1_length - str2_length);
3468}
3469
3470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003471RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 NoHandleAllocation ha;
3473 ASSERT(args.length() == 3);
3474
3475 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003476 int start, end;
3477 // We have a fast integer-only case here to avoid a conversion to double in
3478 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003479 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3480 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3481 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3482 start = from_number;
3483 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003484 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003485 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3486 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003487 start = FastD2I(from_number);
3488 end = FastD2I(to_number);
3489 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490 RUNTIME_ASSERT(end >= start);
3491 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003492 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003493 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003494 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495}
3496
3497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003498RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003499 ASSERT_EQ(3, args.length());
3500
3501 CONVERT_ARG_CHECKED(String, subject, 0);
3502 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3503 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3504 HandleScope handles;
3505
3506 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3507
3508 if (match.is_null()) {
3509 return Failure::Exception();
3510 }
3511 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003512 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003513 }
3514 int length = subject->length();
3515
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003516 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003517 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003518 int start;
3519 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003520 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003521 {
3522 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003523 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003524 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3525 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3526 }
3527 offsets.Add(start);
3528 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003529 if (start == end) if (++end > length) break;
3530 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003531 if (match.is_null()) {
3532 return Failure::Exception();
3533 }
3534 } while (!match->IsNull());
3535 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003536 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003537 Handle<String> substring = isolate->factory()->
3538 NewSubString(subject, offsets.at(0), offsets.at(1));
3539 elements->set(0, *substring);
3540 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003541 int from = offsets.at(i * 2);
3542 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003543 Handle<String> substring = isolate->factory()->
3544 NewProperSubString(subject, from, to);
3545 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003548 result->set_length(Smi::FromInt(matches));
3549 return *result;
3550}
3551
3552
lrn@chromium.org25156de2010-04-06 13:10:27 +00003553// Two smis before and after the match, for very long strings.
3554const int kMaxBuilderEntriesPerRegExpMatch = 5;
3555
3556
3557static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3558 Handle<JSArray> last_match_info,
3559 int match_start,
3560 int match_end) {
3561 // Fill last_match_info with a single capture.
3562 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3563 AssertNoAllocation no_gc;
3564 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3565 RegExpImpl::SetLastCaptureCount(elements, 2);
3566 RegExpImpl::SetLastInput(elements, *subject);
3567 RegExpImpl::SetLastSubject(elements, *subject);
3568 RegExpImpl::SetCapture(elements, 0, match_start);
3569 RegExpImpl::SetCapture(elements, 1, match_end);
3570}
3571
3572
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003573template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003574static bool SearchStringMultiple(Isolate* isolate,
3575 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003576 Vector<const PatternChar> pattern,
3577 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003578 FixedArrayBuilder* builder,
3579 int* match_pos) {
3580 int pos = *match_pos;
3581 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003582 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003583 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003584 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003585 while (pos <= max_search_start) {
3586 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3587 *match_pos = pos;
3588 return false;
3589 }
3590 // Position of end of previous match.
3591 int match_end = pos + pattern_length;
3592 int new_pos = search.Search(subject, match_end);
3593 if (new_pos >= 0) {
3594 // A match.
3595 if (new_pos > match_end) {
3596 ReplacementStringBuilder::AddSubjectSlice(builder,
3597 match_end,
3598 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003599 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003600 pos = new_pos;
3601 builder->Add(pattern_string);
3602 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003603 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003604 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003605 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003606
lrn@chromium.org25156de2010-04-06 13:10:27 +00003607 if (pos < max_search_start) {
3608 ReplacementStringBuilder::AddSubjectSlice(builder,
3609 pos + pattern_length,
3610 subject_length);
3611 }
3612 *match_pos = pos;
3613 return true;
3614}
3615
3616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617static bool SearchStringMultiple(Isolate* isolate,
3618 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003619 Handle<String> pattern,
3620 Handle<JSArray> last_match_info,
3621 FixedArrayBuilder* builder) {
3622 ASSERT(subject->IsFlat());
3623 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003624
3625 // Treating as if a previous match was before first character.
3626 int match_pos = -pattern->length();
3627
3628 for (;;) { // Break when search complete.
3629 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3630 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003631 String::FlatContent subject_content = subject->GetFlatContent();
3632 String::FlatContent pattern_content = pattern->GetFlatContent();
3633 if (subject_content.IsAscii()) {
3634 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3635 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 if (SearchStringMultiple(isolate,
3637 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003638 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003639 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003640 builder,
3641 &match_pos)) break;
3642 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 if (SearchStringMultiple(isolate,
3644 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003645 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003646 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003647 builder,
3648 &match_pos)) break;
3649 }
3650 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003651 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3652 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653 if (SearchStringMultiple(isolate,
3654 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003655 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003657 builder,
3658 &match_pos)) break;
3659 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660 if (SearchStringMultiple(isolate,
3661 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003662 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003663 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003664 builder,
3665 &match_pos)) break;
3666 }
3667 }
3668 }
3669
3670 if (match_pos >= 0) {
3671 SetLastMatchInfoNoCaptures(subject,
3672 last_match_info,
3673 match_pos,
3674 match_pos + pattern->length());
3675 return true;
3676 }
3677 return false; // No matches at all.
3678}
3679
3680
3681static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003682 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 Handle<String> subject,
3684 Handle<JSRegExp> regexp,
3685 Handle<JSArray> last_match_array,
3686 FixedArrayBuilder* builder) {
3687 ASSERT(subject->IsFlat());
3688 int match_start = -1;
3689 int match_end = 0;
3690 int pos = 0;
3691 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3692 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3693
3694 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003695 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003697 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003698
3699 for (;;) { // Break on failure, return on exception.
3700 RegExpImpl::IrregexpResult result =
3701 RegExpImpl::IrregexpExecOnce(regexp,
3702 subject,
3703 pos,
3704 register_vector);
3705 if (result == RegExpImpl::RE_SUCCESS) {
3706 match_start = register_vector[0];
3707 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3708 if (match_end < match_start) {
3709 ReplacementStringBuilder::AddSubjectSlice(builder,
3710 match_end,
3711 match_start);
3712 }
3713 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003714 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003715 if (!first) {
3716 builder->Add(*isolate->factory()->NewProperSubString(subject,
3717 match_start,
3718 match_end));
3719 } else {
3720 builder->Add(*isolate->factory()->NewSubString(subject,
3721 match_start,
3722 match_end));
3723 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003724 if (match_start != match_end) {
3725 pos = match_end;
3726 } else {
3727 pos = match_end + 1;
3728 if (pos > subject_length) break;
3729 }
3730 } else if (result == RegExpImpl::RE_FAILURE) {
3731 break;
3732 } else {
3733 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3734 return result;
3735 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003736 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003737 }
3738
3739 if (match_start >= 0) {
3740 if (match_end < subject_length) {
3741 ReplacementStringBuilder::AddSubjectSlice(builder,
3742 match_end,
3743 subject_length);
3744 }
3745 SetLastMatchInfoNoCaptures(subject,
3746 last_match_array,
3747 match_start,
3748 match_end);
3749 return RegExpImpl::RE_SUCCESS;
3750 } else {
3751 return RegExpImpl::RE_FAILURE; // No matches at all.
3752 }
3753}
3754
3755
3756static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003757 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003758 Handle<String> subject,
3759 Handle<JSRegExp> regexp,
3760 Handle<JSArray> last_match_array,
3761 FixedArrayBuilder* builder) {
3762
3763 ASSERT(subject->IsFlat());
3764 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3765 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3766
3767 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003768 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003769
3770 RegExpImpl::IrregexpResult result =
3771 RegExpImpl::IrregexpExecOnce(regexp,
3772 subject,
3773 0,
3774 register_vector);
3775
3776 int capture_count = regexp->CaptureCount();
3777 int subject_length = subject->length();
3778
3779 // Position to search from.
3780 int pos = 0;
3781 // End of previous match. Differs from pos if match was empty.
3782 int match_end = 0;
3783 if (result == RegExpImpl::RE_SUCCESS) {
3784 // Need to keep a copy of the previous match for creating last_match_info
3785 // at the end, so we have two vectors that we swap between.
3786 OffsetsVector registers2(required_registers);
3787 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003788 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003789 do {
3790 int match_start = register_vector[0];
3791 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3792 if (match_end < match_start) {
3793 ReplacementStringBuilder::AddSubjectSlice(builder,
3794 match_end,
3795 match_start);
3796 }
3797 match_end = register_vector[1];
3798
3799 {
3800 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003802 // Arguments array to replace function is match, captures, index and
3803 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 Handle<FixedArray> elements =
3805 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003806 Handle<String> match;
3807 if (!first) {
3808 match = isolate->factory()->NewProperSubString(subject,
3809 match_start,
3810 match_end);
3811 } else {
3812 match = isolate->factory()->NewSubString(subject,
3813 match_start,
3814 match_end);
3815 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003816 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 for (int i = 1; i <= capture_count; i++) {
3818 int start = register_vector[i * 2];
3819 if (start >= 0) {
3820 int end = register_vector[i * 2 + 1];
3821 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003822 Handle<String> substring;
3823 if (!first) {
3824 substring = isolate->factory()->NewProperSubString(subject,
3825 start,
3826 end);
3827 } else {
3828 substring = isolate->factory()->NewSubString(subject, start, end);
3829 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003830 elements->set(i, *substring);
3831 } else {
3832 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003833 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003834 }
3835 }
3836 elements->set(capture_count + 1, Smi::FromInt(match_start));
3837 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003838 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003839 }
3840 // Swap register vectors, so the last successful match is in
3841 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003842 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003843 prev_register_vector = register_vector;
3844 register_vector = tmp;
3845
3846 if (match_end > match_start) {
3847 pos = match_end;
3848 } else {
3849 pos = match_end + 1;
3850 if (pos > subject_length) {
3851 break;
3852 }
3853 }
3854
3855 result = RegExpImpl::IrregexpExecOnce(regexp,
3856 subject,
3857 pos,
3858 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003859 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003860 } while (result == RegExpImpl::RE_SUCCESS);
3861
3862 if (result != RegExpImpl::RE_EXCEPTION) {
3863 // Finished matching, with at least one match.
3864 if (match_end < subject_length) {
3865 ReplacementStringBuilder::AddSubjectSlice(builder,
3866 match_end,
3867 subject_length);
3868 }
3869
3870 int last_match_capture_count = (capture_count + 1) * 2;
3871 int last_match_array_size =
3872 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3873 last_match_array->EnsureSize(last_match_array_size);
3874 AssertNoAllocation no_gc;
3875 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3876 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3877 RegExpImpl::SetLastSubject(elements, *subject);
3878 RegExpImpl::SetLastInput(elements, *subject);
3879 for (int i = 0; i < last_match_capture_count; i++) {
3880 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3881 }
3882 return RegExpImpl::RE_SUCCESS;
3883 }
3884 }
3885 // No matches at all, return failure or exception result directly.
3886 return result;
3887}
3888
3889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003890RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003893
3894 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003895 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003896 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3897 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3898 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3899
3900 ASSERT(last_match_info->HasFastElements());
3901 ASSERT(regexp->GetFlags().is_global());
3902 Handle<FixedArray> result_elements;
3903 if (result_array->HasFastElements()) {
3904 result_elements =
3905 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003906 }
3907 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003908 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003909 }
3910 FixedArrayBuilder builder(result_elements);
3911
3912 if (regexp->TypeTag() == JSRegExp::ATOM) {
3913 Handle<String> pattern(
3914 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003915 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 if (SearchStringMultiple(isolate, subject, pattern,
3917 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003918 return *builder.ToJSArray(result_array);
3919 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003920 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003921 }
3922
3923 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3924
3925 RegExpImpl::IrregexpResult result;
3926 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 result = SearchRegExpNoCaptureMultiple(isolate,
3928 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003929 regexp,
3930 last_match_info,
3931 &builder);
3932 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003933 result = SearchRegExpMultiple(isolate,
3934 subject,
3935 regexp,
3936 last_match_info,
3937 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003938 }
3939 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003941 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3942 return Failure::Exception();
3943}
3944
3945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003946RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 NoHandleAllocation ha;
3948 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003949 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003950 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003951
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003952 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003953 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003954 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003955 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003956 // Character array used for conversion.
3957 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003958 return isolate->heap()->
3959 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003960 }
3961 }
3962
3963 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003964 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003966 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 }
3968 if (isinf(value)) {
3969 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003970 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 MaybeObject* result =
3976 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 DeleteArray(str);
3978 return result;
3979}
3980
3981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003982RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 NoHandleAllocation ha;
3984 ASSERT(args.length() == 2);
3985
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003986 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 }
3990 if (isinf(value)) {
3991 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003993 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003994 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003996 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003997 int f = FastD2I(f_number);
3998 RUNTIME_ASSERT(f >= 0);
3999 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 MaybeObject* res =
4001 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004002 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004003 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004}
4005
4006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004007RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 NoHandleAllocation ha;
4009 ASSERT(args.length() == 2);
4010
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004011 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
4015 if (isinf(value)) {
4016 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004019 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004021 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 int f = FastD2I(f_number);
4023 RUNTIME_ASSERT(f >= -1 && f <= 20);
4024 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004025 MaybeObject* res =
4026 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004028 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029}
4030
4031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004032RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 NoHandleAllocation ha;
4034 ASSERT(args.length() == 2);
4035
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004036 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 }
4040 if (isinf(value)) {
4041 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004042 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004046 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 int f = FastD2I(f_number);
4048 RUNTIME_ASSERT(f >= 1 && f <= 21);
4049 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004050 MaybeObject* res =
4051 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004053 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054}
4055
4056
4057// Returns a single character string where first character equals
4058// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004059static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004060 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004061 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004062 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004063 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004065 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066}
4067
4068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004069MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4070 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004071 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 // Handle [] indexing on Strings
4073 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004074 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4075 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 }
4077
4078 // Handle [] indexing on String objects
4079 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004080 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4081 Handle<Object> result =
4082 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4083 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 }
4085
4086 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004087 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 return prototype->GetElement(index);
4089 }
4090
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004091 return GetElement(object, index);
4092}
4093
4094
lrn@chromium.org303ada72010-10-27 09:33:13 +00004095MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 return object->GetElement(index);
4097}
4098
4099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4101 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004102 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004103 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004106 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004108 isolate->factory()->NewTypeError("non_object_property_load",
4109 HandleVector(args, 2));
4110 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 }
4112
4113 // Check if the given key is an array index.
4114 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004115 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004116 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 }
4118
4119 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004120 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004122 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 bool has_pending_exception = false;
4125 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004126 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004128 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129 }
4130
ager@chromium.org32912102009-01-16 10:38:43 +00004131 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 // the element if so.
4133 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004134 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004136 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137 }
4138}
4139
4140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004141RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 NoHandleAllocation ha;
4143 ASSERT(args.length() == 2);
4144
4145 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004146 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149}
4150
4151
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004152// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004153RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004154 NoHandleAllocation ha;
4155 ASSERT(args.length() == 2);
4156
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004157 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004158 // itself.
4159 //
4160 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004161 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004162 // global proxy object never has properties. This is the case
4163 // because the global proxy object forwards everything to its hidden
4164 // prototype including local lookups.
4165 //
4166 // Additionally, we need to make sure that we do not cache results
4167 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004168 if (args[0]->IsJSObject() &&
4169 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00004170 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004171 args[1]->IsString()) {
4172 JSObject* receiver = JSObject::cast(args[0]);
4173 String* key = String::cast(args[1]);
4174 if (receiver->HasFastProperties()) {
4175 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004176 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4178 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004179 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004180 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004181 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004182 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004183 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004184 LookupResult result;
4185 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004186 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004187 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004188 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004189 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004190 }
4191 } else {
4192 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004193 StringDictionary* dictionary = receiver->property_dictionary();
4194 int entry = dictionary->FindEntry(key);
4195 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004196 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004197 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004198 if (!receiver->IsGlobalObject()) return value;
4199 value = JSGlobalPropertyCell::cast(value)->value();
4200 if (!value->IsTheHole()) return value;
4201 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004202 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004203 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004204 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4205 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004206 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004207 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004208 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004209 if (index >= 0 && index < str->length()) {
4210 Handle<Object> result = GetCharAt(str, index);
4211 return *result;
4212 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004213 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004214
4215 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 return Runtime::GetObjectProperty(isolate,
4217 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004218 args.at<Object>(1));
4219}
4220
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004221// Implements part of 8.12.9 DefineOwnProperty.
4222// There are 3 cases that lead here:
4223// Step 4b - define a new accessor property.
4224// Steps 9c & 12 - replace an existing data property with an accessor property.
4225// Step 12 - update an existing accessor property with an accessor or generic
4226// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004227RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004228 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004229 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004230 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4231 CONVERT_CHECKED(String, name, args[1]);
4232 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004233 Object* fun = args[3];
4234 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004235 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4236 int unchecked = flag_attr->value();
4237 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4238 RUNTIME_ASSERT(!obj->IsNull());
4239 LookupResult result;
4240 obj->LocalLookupRealNamedProperty(name, &result);
4241
4242 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4243 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4244 // delete it to avoid running into trouble in DefineAccessor, which
4245 // handles this incorrectly if the property is readonly (does nothing)
4246 if (result.IsProperty() &&
4247 (result.type() == FIELD || result.type() == NORMAL
4248 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004249 Object* ok;
4250 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004251 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004252 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4253 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004254 }
4255 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4256}
4257
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004258// Implements part of 8.12.9 DefineOwnProperty.
4259// There are 3 cases that lead here:
4260// Step 4a - define a new data property.
4261// Steps 9b & 12 - replace an existing accessor property with a data property.
4262// Step 12 - update an existing data property with a data or generic
4263// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004264RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004265 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004266 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004267 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4268 CONVERT_ARG_CHECKED(String, name, 1);
4269 Handle<Object> obj_value = args.at<Object>(2);
4270
4271 CONVERT_CHECKED(Smi, flag, args[3]);
4272 int unchecked = flag->value();
4273 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4274
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004275 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4276
4277 // Check if this is an element.
4278 uint32_t index;
4279 bool is_element = name->AsArrayIndex(&index);
4280
4281 // Special case for elements if any of the flags are true.
4282 // If elements are in fast case we always implicitly assume that:
4283 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4284 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4285 is_element) {
4286 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004287 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004288 // We do not need to do access checks here since these has already
4289 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004290 Handle<Object> proto(js_object->GetPrototype());
4291 // If proxy is detached, ignore the assignment. Alternatively,
4292 // we could throw an exception.
4293 if (proto->IsNull()) return *obj_value;
4294 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004295 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004296
4297 // Don't allow element properties to be redefined on objects with external
4298 // array elements.
4299 if (js_object->HasExternalArrayElements()) {
4300 Handle<Object> args[2] = { js_object, name };
4301 Handle<Object> error =
4302 isolate->factory()->NewTypeError("redef_external_array_element",
4303 HandleVector(args, 2));
4304 return isolate->Throw(*error);
4305 }
4306
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004307 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004308 // Make sure that we never go back to fast case.
4309 dictionary->set_requires_slow_elements();
4310 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004311 Handle<NumberDictionary> extended_dictionary =
4312 NumberDictionarySet(dictionary, index, obj_value, details);
4313 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004314 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004315 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4316 } else {
4317 js_object->set_elements(*extended_dictionary);
4318 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004319 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004320 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004321 }
4322
ager@chromium.org5c838252010-02-19 08:53:10 +00004323 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004324 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004325
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004326 // To be compatible with safari we do not change the value on API objects
4327 // in defineProperty. Firefox disagrees here, and actually changes the value.
4328 if (result.IsProperty() &&
4329 (result.type() == CALLBACKS) &&
4330 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004331 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004332 }
4333
ager@chromium.org5c838252010-02-19 08:53:10 +00004334 // Take special care when attributes are different and there is already
4335 // a property. For simplicity we normalize the property which enables us
4336 // to not worry about changing the instance_descriptor and creating a new
4337 // map. The current version of SetObjectProperty does not handle attributes
4338 // correctly in the case where a property is a field and is reset with
4339 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004340 if (result.IsProperty() &&
4341 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004342 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004343 if (js_object->IsJSGlobalProxy()) {
4344 // Since the result is a property, the prototype will exist so
4345 // we don't have to check for null.
4346 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004347 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004348 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004349 // Use IgnoreAttributes version since a readonly property may be
4350 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004351 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4352 *obj_value,
4353 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004354 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 return Runtime::ForceSetObjectProperty(isolate,
4357 js_object,
4358 name,
4359 obj_value,
4360 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004361}
4362
4363
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004364// Special case for elements if any of the flags are true.
4365// If elements are in fast case we always implicitly assume that:
4366// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4367static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4368 Handle<JSObject> js_object,
4369 uint32_t index,
4370 Handle<Object> value,
4371 PropertyAttributes attr) {
4372 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004373 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004374 // Make sure that we never go back to fast case.
4375 dictionary->set_requires_slow_elements();
4376 PropertyDetails details = PropertyDetails(attr, NORMAL);
4377 Handle<NumberDictionary> extended_dictionary =
4378 NumberDictionarySet(dictionary, index, value, details);
4379 if (*extended_dictionary != *dictionary) {
4380 js_object->set_elements(*extended_dictionary);
4381 }
4382 return *value;
4383}
4384
4385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004386MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4387 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004388 Handle<Object> key,
4389 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004390 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004391 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004393
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004394 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004395 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004397 isolate->factory()->NewTypeError("non_object_property_store",
4398 HandleVector(args, 2));
4399 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004400 }
4401
4402 // If the object isn't a JavaScript object, we ignore the store.
4403 if (!object->IsJSObject()) return *value;
4404
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004405 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407 // Check if the given key is an array index.
4408 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004409 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004410 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4411 // of a string using [] notation. We need to support this too in
4412 // JavaScript.
4413 // In the case of a String object we just need to redirect the assignment to
4414 // the underlying string if the index is in range. Since the underlying
4415 // string does nothing with the assignment then we can ignore such
4416 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004417 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004418 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004419 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004420
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004421 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4422 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4423 }
4424
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004425 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004426 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004427 return *value;
4428 }
4429
4430 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004431 Handle<Object> result;
4432 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004433 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4434 return NormalizeObjectSetElement(isolate,
4435 js_object,
4436 index,
4437 value,
4438 attr);
4439 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004440 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004442 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004443 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004444 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004446 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 return *value;
4448 }
4449
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004451 bool has_pending_exception = false;
4452 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4453 if (has_pending_exception) return Failure::Exception();
4454 Handle<String> name = Handle<String>::cast(converted);
4455
4456 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004457 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004459 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 }
4461}
4462
4463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4465 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004466 Handle<Object> key,
4467 Handle<Object> value,
4468 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004469 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004470
4471 // Check if the given key is an array index.
4472 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004473 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004474 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4475 // of a string using [] notation. We need to support this too in
4476 // JavaScript.
4477 // In the case of a String object we just need to redirect the assignment to
4478 // the underlying string if the index is in range. Since the underlying
4479 // string does nothing with the assignment then we can ignore such
4480 // assignments.
4481 if (js_object->IsStringObjectWithCharacterAt(index)) {
4482 return *value;
4483 }
4484
whesse@chromium.org7b260152011-06-20 15:33:18 +00004485 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004486 }
4487
4488 if (key->IsString()) {
4489 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004490 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004491 } else {
4492 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004493 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004494 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4495 *value,
4496 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004497 }
4498 }
4499
4500 // Call-back into JavaScript to convert the key to a string.
4501 bool has_pending_exception = false;
4502 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4503 if (has_pending_exception) return Failure::Exception();
4504 Handle<String> name = Handle<String>::cast(converted);
4505
4506 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004507 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004508 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004509 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004510 }
4511}
4512
4513
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004515 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004516 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004517 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004518
4519 // Check if the given key is an array index.
4520 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004521 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004522 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4523 // characters of a string using [] notation. In the case of a
4524 // String object we just need to redirect the deletion to the
4525 // underlying string if the index is in range. Since the
4526 // underlying string does nothing with the deletion, we can ignore
4527 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004528 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004529 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004530 }
4531
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004532 return JSObject::cast(*receiver)->DeleteElement(
4533 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004534 }
4535
4536 Handle<String> key_string;
4537 if (key->IsString()) {
4538 key_string = Handle<String>::cast(key);
4539 } else {
4540 // Call-back into JavaScript to convert the key to a string.
4541 bool has_pending_exception = false;
4542 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4543 if (has_pending_exception) return Failure::Exception();
4544 key_string = Handle<String>::cast(converted);
4545 }
4546
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004547 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004548 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004549}
4550
4551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004552RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004554 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555
4556 Handle<Object> object = args.at<Object>(0);
4557 Handle<Object> key = args.at<Object>(1);
4558 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004559 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004560 RUNTIME_ASSERT(
4561 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004563 PropertyAttributes attributes =
4564 static_cast<PropertyAttributes>(unchecked_attributes);
4565
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004566 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004567 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004568 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004569 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4570 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004571 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004573
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004574 return Runtime::SetObjectProperty(isolate,
4575 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004576 key,
4577 value,
4578 attributes,
4579 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580}
4581
4582
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004583// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004584// This is used to decide if we should transform null and undefined
4585// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004586RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004587 NoHandleAllocation ha;
4588 RUNTIME_ASSERT(args.length() == 1);
4589
4590 Handle<Object> object = args.at<Object>(0);
4591
4592 if (object->IsJSFunction()) {
4593 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004594 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004595 }
4596 return isolate->heap()->undefined_value();
4597}
4598
4599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600// Set a local property, even if it is READ_ONLY. If the property does not
4601// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004602RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004604 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605 CONVERT_CHECKED(JSObject, object, args[0]);
4606 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004607 // Compute attributes.
4608 PropertyAttributes attributes = NONE;
4609 if (args.length() == 4) {
4610 CONVERT_CHECKED(Smi, value_obj, args[3]);
4611 int unchecked_value = value_obj->value();
4612 // Only attribute bits should be set.
4613 RUNTIME_ASSERT(
4614 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4615 attributes = static_cast<PropertyAttributes>(unchecked_value);
4616 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004617
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004618 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004619 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004620}
4621
4622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004623RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004624 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004625 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004627 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004629 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004630 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004631 ? JSReceiver::STRICT_DELETION
4632 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633}
4634
4635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636static Object* HasLocalPropertyImplementation(Isolate* isolate,
4637 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004638 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004639 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004640 // Handle hidden prototypes. If there's a hidden prototype above this thing
4641 // then we have to check it for properties, because they are supposed to
4642 // look like they are on this object.
4643 Handle<Object> proto(object->GetPrototype());
4644 if (proto->IsJSObject() &&
4645 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004646 return HasLocalPropertyImplementation(isolate,
4647 Handle<JSObject>::cast(proto),
4648 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004649 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004651}
4652
4653
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004654RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004655 NoHandleAllocation ha;
4656 ASSERT(args.length() == 2);
4657 CONVERT_CHECKED(String, key, args[1]);
4658
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004659 uint32_t index;
4660 const bool key_is_array_index = key->AsArrayIndex(&index);
4661
ager@chromium.org9085a012009-05-11 19:22:57 +00004662 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004663 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004664 if (obj->IsJSObject()) {
4665 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004666 // Fast case: either the key is a real named property or it is not
4667 // an array index and there are no interceptors or hidden
4668 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004669 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004670 Map* map = object->map();
4671 if (!key_is_array_index &&
4672 !map->has_named_interceptor() &&
4673 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4674 return isolate->heap()->false_value();
4675 }
4676 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004677 HandleScope scope(isolate);
4678 return HasLocalPropertyImplementation(isolate,
4679 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004680 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004681 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004682 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004683 String* string = String::cast(obj);
4684 if (index < static_cast<uint32_t>(string->length())) {
4685 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686 }
4687 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004688 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689}
4690
4691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 NoHandleAllocation na;
4694 ASSERT(args.length() == 2);
4695
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004696 // Only JS receivers can have properties.
4697 if (args[0]->IsJSReceiver()) {
4698 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004699 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004700 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004702 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703}
4704
4705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004706RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 NoHandleAllocation na;
4708 ASSERT(args.length() == 2);
4709
4710 // Only JS objects can have elements.
4711 if (args[0]->IsJSObject()) {
4712 JSObject* object = JSObject::cast(args[0]);
4713 CONVERT_CHECKED(Smi, index_obj, args[1]);
4714 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004717 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718}
4719
4720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004721RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722 NoHandleAllocation ha;
4723 ASSERT(args.length() == 2);
4724
4725 CONVERT_CHECKED(JSObject, object, args[0]);
4726 CONVERT_CHECKED(String, key, args[1]);
4727
4728 uint32_t index;
4729 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004730 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731 }
4732
ager@chromium.org870a0b62008-11-04 11:43:05 +00004733 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004734 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735}
4736
4737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004738RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004739 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004741 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 return *GetKeysFor(object);
4743}
4744
4745
4746// Returns either a FixedArray as Runtime_GetPropertyNames,
4747// or, if the given object has an enum cache that contains
4748// all enumerable properties of the object and its prototypes
4749// have none, the map of the object. This is used to speed up
4750// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004751RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752 ASSERT(args.length() == 1);
4753
4754 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4755
4756 if (raw_object->IsSimpleEnum()) return raw_object->map();
4757
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004758 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004760 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4761 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762
4763 // Test again, since cache may have been built by preceding call.
4764 if (object->IsSimpleEnum()) return object->map();
4765
4766 return *content;
4767}
4768
4769
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004770// Find the length of the prototype chain that is to to handled as one. If a
4771// prototype object is hidden it is to be viewed as part of the the object it
4772// is prototype for.
4773static int LocalPrototypeChainLength(JSObject* obj) {
4774 int count = 1;
4775 Object* proto = obj->GetPrototype();
4776 while (proto->IsJSObject() &&
4777 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4778 count++;
4779 proto = JSObject::cast(proto)->GetPrototype();
4780 }
4781 return count;
4782}
4783
4784
4785// Return the names of the local named properties.
4786// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004787RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004788 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004789 ASSERT(args.length() == 1);
4790 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004791 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004792 }
4793 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4794
4795 // Skip the global proxy as it has no properties and always delegates to the
4796 // real global object.
4797 if (obj->IsJSGlobalProxy()) {
4798 // Only collect names if access is permitted.
4799 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004800 !isolate->MayNamedAccess(*obj,
4801 isolate->heap()->undefined_value(),
4802 v8::ACCESS_KEYS)) {
4803 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4804 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004805 }
4806 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4807 }
4808
4809 // Find the number of objects making up this.
4810 int length = LocalPrototypeChainLength(*obj);
4811
4812 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004813 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004814 int total_property_count = 0;
4815 Handle<JSObject> jsproto = obj;
4816 for (int i = 0; i < length; i++) {
4817 // Only collect names if access is permitted.
4818 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004819 !isolate->MayNamedAccess(*jsproto,
4820 isolate->heap()->undefined_value(),
4821 v8::ACCESS_KEYS)) {
4822 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4823 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004824 }
4825 int n;
4826 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4827 local_property_count[i] = n;
4828 total_property_count += n;
4829 if (i < length - 1) {
4830 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4831 }
4832 }
4833
4834 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004835 Handle<FixedArray> names =
4836 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004837
4838 // Get the property names.
4839 jsproto = obj;
4840 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004841 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004842 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004843 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4844 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004845 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004846 proto_with_hidden_properties++;
4847 }
4848 if (i < length - 1) {
4849 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4850 }
4851 }
4852
4853 // Filter out name of hidden propeties object.
4854 if (proto_with_hidden_properties > 0) {
4855 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004856 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004857 names->length() - proto_with_hidden_properties);
4858 int dest_pos = 0;
4859 for (int i = 0; i < total_property_count; i++) {
4860 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004862 continue;
4863 }
4864 names->set(dest_pos++, name);
4865 }
4866 }
4867
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004869}
4870
4871
4872// Return the names of the local indexed properties.
4873// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004874RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004876 ASSERT(args.length() == 1);
4877 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004878 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004879 }
4880 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4881
4882 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004883 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004884 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004885 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004886}
4887
4888
4889// Return information on whether an object has a named or indexed interceptor.
4890// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004892 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004893 ASSERT(args.length() == 1);
4894 if (!args[0]->IsJSObject()) {
4895 return Smi::FromInt(0);
4896 }
4897 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4898
4899 int result = 0;
4900 if (obj->HasNamedInterceptor()) result |= 2;
4901 if (obj->HasIndexedInterceptor()) result |= 1;
4902
4903 return Smi::FromInt(result);
4904}
4905
4906
4907// Return property names from named interceptor.
4908// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004909RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004910 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004911 ASSERT(args.length() == 1);
4912 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4913
4914 if (obj->HasNamedInterceptor()) {
4915 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4916 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4917 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004918 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004919}
4920
4921
4922// Return element names from indexed interceptor.
4923// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004924RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004925 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004926 ASSERT(args.length() == 1);
4927 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4928
4929 if (obj->HasIndexedInterceptor()) {
4930 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4931 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4932 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004933 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004934}
4935
4936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004937RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004938 ASSERT_EQ(args.length(), 1);
4939 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004940 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004941 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004942
4943 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004944 // Do access checks before going to the global object.
4945 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004946 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004947 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4949 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004950 }
4951
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004952 Handle<Object> proto(object->GetPrototype());
4953 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004954 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004955 object = Handle<JSObject>::cast(proto);
4956 }
4957
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004958 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4959 LOCAL_ONLY);
4960 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4961 // property array and since the result is mutable we have to create
4962 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004963 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004964 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004965 for (int i = 0; i < length; i++) {
4966 Object* entry = contents->get(i);
4967 if (entry->IsString()) {
4968 copy->set(i, entry);
4969 } else {
4970 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004971 HandleScope scope(isolate);
4972 Handle<Object> entry_handle(entry, isolate);
4973 Handle<Object> entry_str =
4974 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004975 copy->set(i, *entry_str);
4976 }
4977 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004978 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004979}
4980
4981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004982RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004983 NoHandleAllocation ha;
4984 ASSERT(args.length() == 1);
4985
4986 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004987 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004988 it.AdvanceToArgumentsFrame();
4989 JavaScriptFrame* frame = it.frame();
4990
4991 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004992 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004993
4994 // Try to convert the key to an index. If successful and within
4995 // index return the the argument from the frame.
4996 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004997 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 return frame->GetParameter(index);
4999 }
5000
5001 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005002 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005003 bool exception = false;
5004 Handle<Object> converted =
5005 Execution::ToString(args.at<Object>(0), &exception);
5006 if (exception) return Failure::Exception();
5007 Handle<String> key = Handle<String>::cast(converted);
5008
5009 // Try to convert the string key into an array index.
5010 if (key->AsArrayIndex(&index)) {
5011 if (index < n) {
5012 return frame->GetParameter(index);
5013 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005015 }
5016 }
5017
5018 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005019 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5020 if (key->Equals(isolate->heap()->callee_symbol())) {
5021 Object* function = frame->function();
5022 if (function->IsJSFunction() &&
5023 JSFunction::cast(function)->shared()->strict_mode()) {
5024 return isolate->Throw(*isolate->factory()->NewTypeError(
5025 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5026 }
5027 return function;
5028 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005029
5030 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005032}
5033
5034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005035RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005036 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005037
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005038 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005039 Handle<Object> object = args.at<Object>(0);
5040 if (object->IsJSObject()) {
5041 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005042 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005043 MaybeObject* ok = js_object->TransformToFastProperties(0);
5044 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005045 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005046 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005047 return *object;
5048}
5049
5050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005051RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005053
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005054 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005055 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005056 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005057 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005058 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005059 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005060 return *object;
5061}
5062
5063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005064RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005065 NoHandleAllocation ha;
5066 ASSERT(args.length() == 1);
5067
5068 return args[0]->ToBoolean();
5069}
5070
5071
5072// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5073// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005074RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005075 NoHandleAllocation ha;
5076
5077 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005079 HeapObject* heap_obj = HeapObject::cast(obj);
5080
5081 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005082 if (heap_obj->map()->is_undetectable()) {
5083 return isolate->heap()->undefined_symbol();
5084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005085
5086 InstanceType instance_type = heap_obj->map()->instance_type();
5087 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005089 }
5090
5091 switch (instance_type) {
5092 case ODDBALL_TYPE:
5093 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 }
5096 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005097 return FLAG_harmony_typeof
5098 ? isolate->heap()->null_symbol()
5099 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005100 }
5101 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005102 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005103 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005104 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005105 default:
5106 // For any kind of object not handled above, the spec rule for
5107 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005109 }
5110}
5111
5112
lrn@chromium.org25156de2010-04-06 13:10:27 +00005113static bool AreDigits(const char*s, int from, int to) {
5114 for (int i = from; i < to; i++) {
5115 if (s[i] < '0' || s[i] > '9') return false;
5116 }
5117
5118 return true;
5119}
5120
5121
5122static int ParseDecimalInteger(const char*s, int from, int to) {
5123 ASSERT(to - from < 10); // Overflow is not possible.
5124 ASSERT(from < to);
5125 int d = s[from] - '0';
5126
5127 for (int i = from + 1; i < to; i++) {
5128 d = 10 * d + (s[i] - '0');
5129 }
5130
5131 return d;
5132}
5133
5134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005135RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136 NoHandleAllocation ha;
5137 ASSERT(args.length() == 1);
5138 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005139 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005140
5141 // Fast case: short integer or some sorts of junk values.
5142 int len = subject->length();
5143 if (subject->IsSeqAsciiString()) {
5144 if (len == 0) return Smi::FromInt(0);
5145
5146 char const* data = SeqAsciiString::cast(subject)->GetChars();
5147 bool minus = (data[0] == '-');
5148 int start_pos = (minus ? 1 : 0);
5149
5150 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005151 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005152 } else if (data[start_pos] > '9') {
5153 // Fast check for a junk value. A valid string may start from a
5154 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5155 // the 'I' character ('Infinity'). All of that have codes not greater than
5156 // '9' except 'I'.
5157 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005158 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005159 }
5160 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5161 // The maximal/minimal smi has 10 digits. If the string has less digits we
5162 // know it will fit into the smi-data type.
5163 int d = ParseDecimalInteger(data, start_pos, len);
5164 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005166 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005167 } else if (!subject->HasHashCode() &&
5168 len <= String::kMaxArrayIndexSize &&
5169 (len == 1 || data[0] != '0')) {
5170 // String hash is not calculated yet but all the data are present.
5171 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005172 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005173#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005174 subject->Hash(); // Force hash calculation.
5175 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5176 static_cast<int>(hash));
5177#endif
5178 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005179 }
5180 return Smi::FromInt(d);
5181 }
5182 }
5183
5184 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005185 return isolate->heap()->NumberFromDouble(
5186 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187}
5188
5189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005190RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191 NoHandleAllocation ha;
5192 ASSERT(args.length() == 1);
5193
5194 CONVERT_CHECKED(JSArray, codes, args[0]);
5195 int length = Smi::cast(codes->length())->value();
5196
5197 // Check if the string can be ASCII.
5198 int i;
5199 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005200 Object* element;
5201 { MaybeObject* maybe_element = codes->GetElement(i);
5202 // We probably can't get an exception here, but just in order to enforce
5203 // the checking of inputs in the runtime calls we check here.
5204 if (!maybe_element->ToObject(&element)) return maybe_element;
5205 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5207 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5208 break;
5209 }
5210
lrn@chromium.org303ada72010-10-27 09:33:13 +00005211 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 }
5217
lrn@chromium.org303ada72010-10-27 09:33:13 +00005218 Object* object = NULL;
5219 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 String* result = String::cast(object);
5221 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005222 Object* element;
5223 { MaybeObject* maybe_element = codes->GetElement(i);
5224 if (!maybe_element->ToObject(&element)) return maybe_element;
5225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005227 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 }
5229 return result;
5230}
5231
5232
5233// kNotEscaped is generated by the following:
5234//
5235// #!/bin/perl
5236// for (my $i = 0; $i < 256; $i++) {
5237// print "\n" if $i % 16 == 0;
5238// my $c = chr($i);
5239// my $escaped = 1;
5240// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5241// print $escaped ? "0, " : "1, ";
5242// }
5243
5244
5245static bool IsNotEscaped(uint16_t character) {
5246 // Only for 8 bit characters, the rest are always escaped (in a different way)
5247 ASSERT(character < 256);
5248 static const char kNotEscaped[256] = {
5249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5252 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5253 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5254 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5255 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5256 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5257 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5258 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5259 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5261 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5262 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5265 };
5266 return kNotEscaped[character] != 0;
5267}
5268
5269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005270RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271 const char hex_chars[] = "0123456789ABCDEF";
5272 NoHandleAllocation ha;
5273 ASSERT(args.length() == 1);
5274 CONVERT_CHECKED(String, source, args[0]);
5275
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005276 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005277
5278 int escaped_length = 0;
5279 int length = source->length();
5280 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005281 Access<StringInputBuffer> buffer(
5282 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005283 buffer->Reset(source);
5284 while (buffer->has_more()) {
5285 uint16_t character = buffer->GetNext();
5286 if (character >= 256) {
5287 escaped_length += 6;
5288 } else if (IsNotEscaped(character)) {
5289 escaped_length++;
5290 } else {
5291 escaped_length += 3;
5292 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005293 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005294 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005295 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005297 return Failure::OutOfMemoryException();
5298 }
5299 }
5300 }
5301 // No length change implies no change. Return original string if no change.
5302 if (escaped_length == length) {
5303 return source;
5304 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005305 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005306 { MaybeObject* maybe_o =
5307 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005308 if (!maybe_o->ToObject(&o)) return maybe_o;
5309 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005310 String* destination = String::cast(o);
5311 int dest_position = 0;
5312
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005313 Access<StringInputBuffer> buffer(
5314 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 buffer->Rewind();
5316 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005317 uint16_t chr = buffer->GetNext();
5318 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005319 destination->Set(dest_position, '%');
5320 destination->Set(dest_position+1, 'u');
5321 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5322 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5323 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5324 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005326 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005327 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005328 dest_position++;
5329 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005330 destination->Set(dest_position, '%');
5331 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5332 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 dest_position += 3;
5334 }
5335 }
5336 return destination;
5337}
5338
5339
5340static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5341 static const signed char kHexValue['g'] = {
5342 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5343 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5344 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5345 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5346 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5347 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5348 -1, 10, 11, 12, 13, 14, 15 };
5349
5350 if (character1 > 'f') return -1;
5351 int hi = kHexValue[character1];
5352 if (hi == -1) return -1;
5353 if (character2 > 'f') return -1;
5354 int lo = kHexValue[character2];
5355 if (lo == -1) return -1;
5356 return (hi << 4) + lo;
5357}
5358
5359
ager@chromium.org870a0b62008-11-04 11:43:05 +00005360static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005361 int i,
5362 int length,
5363 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005364 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005365 int32_t hi = 0;
5366 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005367 if (character == '%' &&
5368 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005369 source->Get(i + 1) == 'u' &&
5370 (hi = TwoDigitHex(source->Get(i + 2),
5371 source->Get(i + 3))) != -1 &&
5372 (lo = TwoDigitHex(source->Get(i + 4),
5373 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 *step = 6;
5375 return (hi << 8) + lo;
5376 } else if (character == '%' &&
5377 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005378 (lo = TwoDigitHex(source->Get(i + 1),
5379 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380 *step = 3;
5381 return lo;
5382 } else {
5383 *step = 1;
5384 return character;
5385 }
5386}
5387
5388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005389RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 NoHandleAllocation ha;
5391 ASSERT(args.length() == 1);
5392 CONVERT_CHECKED(String, source, args[0]);
5393
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005394 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395
5396 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005397 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398
5399 int unescaped_length = 0;
5400 for (int i = 0; i < length; unescaped_length++) {
5401 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005402 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005404 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405 i += step;
5406 }
5407
5408 // No length change implies no change. Return original string if no change.
5409 if (unescaped_length == length)
5410 return source;
5411
lrn@chromium.org303ada72010-10-27 09:33:13 +00005412 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005413 { MaybeObject* maybe_o =
5414 ascii ?
5415 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5416 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005417 if (!maybe_o->ToObject(&o)) return maybe_o;
5418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419 String* destination = String::cast(o);
5420
5421 int dest_position = 0;
5422 for (int i = 0; i < length; dest_position++) {
5423 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005424 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005425 i += step;
5426 }
5427 return destination;
5428}
5429
5430
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005431static const unsigned int kQuoteTableLength = 128u;
5432
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005433static const int kJsonQuotesCharactersPerEntry = 8;
5434static const char* const JsonQuotes =
5435 "\\u0000 \\u0001 \\u0002 \\u0003 "
5436 "\\u0004 \\u0005 \\u0006 \\u0007 "
5437 "\\b \\t \\n \\u000b "
5438 "\\f \\r \\u000e \\u000f "
5439 "\\u0010 \\u0011 \\u0012 \\u0013 "
5440 "\\u0014 \\u0015 \\u0016 \\u0017 "
5441 "\\u0018 \\u0019 \\u001a \\u001b "
5442 "\\u001c \\u001d \\u001e \\u001f "
5443 " ! \\\" # "
5444 "$ % & ' "
5445 "( ) * + "
5446 ", - . / "
5447 "0 1 2 3 "
5448 "4 5 6 7 "
5449 "8 9 : ; "
5450 "< = > ? "
5451 "@ A B C "
5452 "D E F G "
5453 "H I J K "
5454 "L M N O "
5455 "P Q R S "
5456 "T U V W "
5457 "X Y Z [ "
5458 "\\\\ ] ^ _ "
5459 "` a b c "
5460 "d e f g "
5461 "h i j k "
5462 "l m n o "
5463 "p q r s "
5464 "t u v w "
5465 "x y z { "
5466 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005467
5468
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005469// For a string that is less than 32k characters it should always be
5470// possible to allocate it in new space.
5471static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5472
5473
5474// Doing JSON quoting cannot make the string more than this many times larger.
5475static const int kJsonQuoteWorstCaseBlowup = 6;
5476
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005477static const int kSpaceForQuotesAndComma = 3;
5478static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005479
5480// Covers the entire ASCII range (all other characters are unchanged by JSON
5481// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005482static const byte JsonQuoteLengths[kQuoteTableLength] = {
5483 6, 6, 6, 6, 6, 6, 6, 6,
5484 2, 2, 2, 6, 2, 2, 6, 6,
5485 6, 6, 6, 6, 6, 6, 6, 6,
5486 6, 6, 6, 6, 6, 6, 6, 6,
5487 1, 1, 2, 1, 1, 1, 1, 1,
5488 1, 1, 1, 1, 1, 1, 1, 1,
5489 1, 1, 1, 1, 1, 1, 1, 1,
5490 1, 1, 1, 1, 1, 1, 1, 1,
5491 1, 1, 1, 1, 1, 1, 1, 1,
5492 1, 1, 1, 1, 1, 1, 1, 1,
5493 1, 1, 1, 1, 1, 1, 1, 1,
5494 1, 1, 1, 1, 2, 1, 1, 1,
5495 1, 1, 1, 1, 1, 1, 1, 1,
5496 1, 1, 1, 1, 1, 1, 1, 1,
5497 1, 1, 1, 1, 1, 1, 1, 1,
5498 1, 1, 1, 1, 1, 1, 1, 1,
5499};
5500
5501
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005502template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005503MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005504
5505
5506template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005507MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5508 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005509}
5510
5511
5512template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005513MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5514 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005515}
5516
5517
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005518template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005519static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5520 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005521 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005522 const Char* read_cursor = characters.start();
5523 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005524 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005525 int quoted_length = kSpaceForQuotes;
5526 while (read_cursor < end) {
5527 Char c = *(read_cursor++);
5528 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5529 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005530 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005531 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005532 }
5533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005534 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5535 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005536 Object* new_object;
5537 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005538 return new_alloc;
5539 }
5540 StringType* new_string = StringType::cast(new_object);
5541
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005542 Char* write_cursor = reinterpret_cast<Char*>(
5543 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005544 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005545 *(write_cursor++) = '"';
5546
5547 read_cursor = characters.start();
5548 while (read_cursor < end) {
5549 Char c = *(read_cursor++);
5550 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5551 *(write_cursor++) = c;
5552 } else {
5553 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5554 const char* replacement = JsonQuotes +
5555 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5556 for (int i = 0; i < len; i++) {
5557 *write_cursor++ = *replacement++;
5558 }
5559 }
5560 }
5561 *(write_cursor++) = '"';
5562 return new_string;
5563}
5564
5565
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005566template <typename SinkChar, typename SourceChar>
5567static inline SinkChar* WriteQuoteJsonString(
5568 Isolate* isolate,
5569 SinkChar* write_cursor,
5570 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005571 // SinkChar is only char if SourceChar is guaranteed to be char.
5572 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005573 const SourceChar* read_cursor = characters.start();
5574 const SourceChar* end = read_cursor + characters.length();
5575 *(write_cursor++) = '"';
5576 while (read_cursor < end) {
5577 SourceChar c = *(read_cursor++);
5578 if (sizeof(SourceChar) > 1u &&
5579 static_cast<unsigned>(c) >= kQuoteTableLength) {
5580 *(write_cursor++) = static_cast<SinkChar>(c);
5581 } else {
5582 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5583 const char* replacement = JsonQuotes +
5584 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5585 write_cursor[0] = replacement[0];
5586 if (len > 1) {
5587 write_cursor[1] = replacement[1];
5588 if (len > 2) {
5589 ASSERT(len == 6);
5590 write_cursor[2] = replacement[2];
5591 write_cursor[3] = replacement[3];
5592 write_cursor[4] = replacement[4];
5593 write_cursor[5] = replacement[5];
5594 }
5595 }
5596 write_cursor += len;
5597 }
5598 }
5599 *(write_cursor++) = '"';
5600 return write_cursor;
5601}
5602
5603
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005604template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005605static MaybeObject* QuoteJsonString(Isolate* isolate,
5606 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005607 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005608 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005609 int worst_case_length =
5610 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005611 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005612 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005613 }
5614
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005615 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5616 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005617 Object* new_object;
5618 if (!new_alloc->ToObject(&new_object)) {
5619 return new_alloc;
5620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005621 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005622 // Even if our string is small enough to fit in new space we still have to
5623 // handle it being allocated in old space as may happen in the third
5624 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5625 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005626 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005627 }
5628 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005629 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005630
5631 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5632 Char* write_cursor = reinterpret_cast<Char*>(
5633 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005634 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005635 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5636 write_cursor,
5637 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005638 int final_length = static_cast<int>(
5639 write_cursor - reinterpret_cast<Char*>(
5640 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005641 isolate->heap()->new_space()->
5642 template ShrinkStringAtAllocationBoundary<StringType>(
5643 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005644 return new_string;
5645}
5646
5647
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005648RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005649 NoHandleAllocation ha;
5650 CONVERT_CHECKED(String, str, args[0]);
5651 if (!str->IsFlat()) {
5652 MaybeObject* try_flatten = str->TryFlatten();
5653 Object* flat;
5654 if (!try_flatten->ToObject(&flat)) {
5655 return try_flatten;
5656 }
5657 str = String::cast(flat);
5658 ASSERT(str->IsFlat());
5659 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005660 String::FlatContent flat = str->GetFlatContent();
5661 ASSERT(flat.IsFlat());
5662 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005663 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005664 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005665 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005666 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005667 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005668 }
5669}
5670
5671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005672RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005673 NoHandleAllocation ha;
5674 CONVERT_CHECKED(String, str, args[0]);
5675 if (!str->IsFlat()) {
5676 MaybeObject* try_flatten = str->TryFlatten();
5677 Object* flat;
5678 if (!try_flatten->ToObject(&flat)) {
5679 return try_flatten;
5680 }
5681 str = String::cast(flat);
5682 ASSERT(str->IsFlat());
5683 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005684 String::FlatContent flat = str->GetFlatContent();
5685 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005687 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005688 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005689 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005690 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005691 }
5692}
5693
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005694
5695template <typename Char, typename StringType>
5696static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5697 FixedArray* array,
5698 int worst_case_length) {
5699 int length = array->length();
5700
5701 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5702 worst_case_length);
5703 Object* new_object;
5704 if (!new_alloc->ToObject(&new_object)) {
5705 return new_alloc;
5706 }
5707 if (!isolate->heap()->new_space()->Contains(new_object)) {
5708 // Even if our string is small enough to fit in new space we still have to
5709 // handle it being allocated in old space as may happen in the third
5710 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5711 // CEntryStub::GenerateCore.
5712 return isolate->heap()->undefined_value();
5713 }
5714 AssertNoAllocation no_gc;
5715 StringType* new_string = StringType::cast(new_object);
5716 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5717
5718 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5719 Char* write_cursor = reinterpret_cast<Char*>(
5720 new_string->address() + SeqAsciiString::kHeaderSize);
5721 *(write_cursor++) = '[';
5722 for (int i = 0; i < length; i++) {
5723 if (i != 0) *(write_cursor++) = ',';
5724 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005725 String::FlatContent content = str->GetFlatContent();
5726 ASSERT(content.IsFlat());
5727 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005728 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5729 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005730 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005731 } else {
5732 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5733 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005734 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005735 }
5736 }
5737 *(write_cursor++) = ']';
5738
5739 int final_length = static_cast<int>(
5740 write_cursor - reinterpret_cast<Char*>(
5741 new_string->address() + SeqAsciiString::kHeaderSize));
5742 isolate->heap()->new_space()->
5743 template ShrinkStringAtAllocationBoundary<StringType>(
5744 new_string, final_length);
5745 return new_string;
5746}
5747
5748
5749RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5750 NoHandleAllocation ha;
5751 ASSERT(args.length() == 1);
5752 CONVERT_CHECKED(JSArray, array, args[0]);
5753
5754 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5755 FixedArray* elements = FixedArray::cast(array->elements());
5756 int n = elements->length();
5757 bool ascii = true;
5758 int total_length = 0;
5759
5760 for (int i = 0; i < n; i++) {
5761 Object* elt = elements->get(i);
5762 if (!elt->IsString()) return isolate->heap()->undefined_value();
5763 String* element = String::cast(elt);
5764 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5765 total_length += element->length();
5766 if (ascii && element->IsTwoByteRepresentation()) {
5767 ascii = false;
5768 }
5769 }
5770
5771 int worst_case_length =
5772 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5773 + total_length * kJsonQuoteWorstCaseBlowup;
5774
5775 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5776 return isolate->heap()->undefined_value();
5777 }
5778
5779 if (ascii) {
5780 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5781 elements,
5782 worst_case_length);
5783 } else {
5784 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5785 elements,
5786 worst_case_length);
5787 }
5788}
5789
5790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005791RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792 NoHandleAllocation ha;
5793
5794 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005795 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005796
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005797 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005798
lrn@chromium.org25156de2010-04-06 13:10:27 +00005799 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005800 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802}
5803
5804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005805RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 NoHandleAllocation ha;
5807 CONVERT_CHECKED(String, str, args[0]);
5808
5809 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005810 double value = StringToDouble(isolate->unicode_cache(),
5811 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812
5813 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005814 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005815}
5816
5817
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005818template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005819MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005820 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005821 String* s,
5822 int length,
5823 int input_string_length,
5824 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005825 // We try this twice, once with the assumption that the result is no longer
5826 // than the input and, if that assumption breaks, again with the exact
5827 // length. This may not be pretty, but it is nicer than what was here before
5828 // and I hereby claim my vaffel-is.
5829 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005830 // Allocate the resulting string.
5831 //
5832 // NOTE: This assumes that the upper/lower case of an ascii
5833 // character is also ascii. This is currently the case, but it
5834 // might break in the future if we implement more context and locale
5835 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005836 Object* o;
5837 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005838 ? isolate->heap()->AllocateRawAsciiString(length)
5839 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005840 if (!maybe_o->ToObject(&o)) return maybe_o;
5841 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005842 String* result = String::cast(o);
5843 bool has_changed_character = false;
5844
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845 // Convert all characters to upper case, assuming that they will fit
5846 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005847 Access<StringInputBuffer> buffer(
5848 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005849 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005850 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005851 // We can assume that the string is not empty
5852 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005853 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005854 bool has_next = buffer->has_more();
5855 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005856 int char_length = mapping->get(current, next, chars);
5857 if (char_length == 0) {
5858 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005859 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005860 i++;
5861 } else if (char_length == 1) {
5862 // Common case: converting the letter resulted in one character.
5863 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005864 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005865 has_changed_character = true;
5866 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005867 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 // We've assumed that the result would be as long as the
5869 // input but here is a character that converts to several
5870 // characters. No matter, we calculate the exact length
5871 // of the result and try the whole thing again.
5872 //
5873 // Note that this leaves room for optimization. We could just
5874 // memcpy what we already have to the result string. Also,
5875 // the result string is the last object allocated we could
5876 // "realloc" it and probably, in the vast majority of cases,
5877 // extend the existing string to be able to hold the full
5878 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005879 int next_length = 0;
5880 if (has_next) {
5881 next_length = mapping->get(next, 0, chars);
5882 if (next_length == 0) next_length = 1;
5883 }
5884 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005885 while (buffer->has_more()) {
5886 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005887 // NOTE: we use 0 as the next character here because, while
5888 // the next character may affect what a character converts to,
5889 // it does not in any case affect the length of what it convert
5890 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005891 int char_length = mapping->get(current, 0, chars);
5892 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005893 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005894 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005895 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005896 return Failure::OutOfMemoryException();
5897 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005898 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005899 // Try again with the real length.
5900 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901 } else {
5902 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005903 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904 i++;
5905 }
5906 has_changed_character = true;
5907 }
5908 current = next;
5909 }
5910 if (has_changed_character) {
5911 return result;
5912 } else {
5913 // If we didn't actually change anything in doing the conversion
5914 // we simple return the result and let the converted string
5915 // become garbage; there is no reason to keep two identical strings
5916 // alive.
5917 return s;
5918 }
5919}
5920
5921
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005922namespace {
5923
lrn@chromium.org303ada72010-10-27 09:33:13 +00005924static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5925
5926
5927// Given a word and two range boundaries returns a word with high bit
5928// set in every byte iff the corresponding input byte was strictly in
5929// the range (m, n). All the other bits in the result are cleared.
5930// This function is only useful when it can be inlined and the
5931// boundaries are statically known.
5932// Requires: all bytes in the input word and the boundaries must be
5933// ascii (less than 0x7F).
5934static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5935 // Every byte in an ascii string is less than or equal to 0x7F.
5936 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5937 // Use strict inequalities since in edge cases the function could be
5938 // further simplified.
5939 ASSERT(0 < m && m < n && n < 0x7F);
5940 // Has high bit set in every w byte less than n.
5941 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5942 // Has high bit set in every w byte greater than m.
5943 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5944 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5945}
5946
5947
5948enum AsciiCaseConversion {
5949 ASCII_TO_LOWER,
5950 ASCII_TO_UPPER
5951};
5952
5953
5954template <AsciiCaseConversion dir>
5955struct FastAsciiConverter {
5956 static bool Convert(char* dst, char* src, int length) {
5957#ifdef DEBUG
5958 char* saved_dst = dst;
5959 char* saved_src = src;
5960#endif
5961 // We rely on the distance between upper and lower case letters
5962 // being a known power of 2.
5963 ASSERT('a' - 'A' == (1 << 5));
5964 // Boundaries for the range of input characters than require conversion.
5965 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5966 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5967 bool changed = false;
5968 char* const limit = src + length;
5969#ifdef V8_HOST_CAN_READ_UNALIGNED
5970 // Process the prefix of the input that requires no conversion one
5971 // (machine) word at a time.
5972 while (src <= limit - sizeof(uintptr_t)) {
5973 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5974 if (AsciiRangeMask(w, lo, hi) != 0) {
5975 changed = true;
5976 break;
5977 }
5978 *reinterpret_cast<uintptr_t*>(dst) = w;
5979 src += sizeof(uintptr_t);
5980 dst += sizeof(uintptr_t);
5981 }
5982 // Process the remainder of the input performing conversion when
5983 // required one word at a time.
5984 while (src <= limit - sizeof(uintptr_t)) {
5985 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5986 uintptr_t m = AsciiRangeMask(w, lo, hi);
5987 // The mask has high (7th) bit set in every byte that needs
5988 // conversion and we know that the distance between cases is
5989 // 1 << 5.
5990 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5991 src += sizeof(uintptr_t);
5992 dst += sizeof(uintptr_t);
5993 }
5994#endif
5995 // Process the last few bytes of the input (or the whole input if
5996 // unaligned access is not supported).
5997 while (src < limit) {
5998 char c = *src;
5999 if (lo < c && c < hi) {
6000 c ^= (1 << 5);
6001 changed = true;
6002 }
6003 *dst = c;
6004 ++src;
6005 ++dst;
6006 }
6007#ifdef DEBUG
6008 CheckConvert(saved_dst, saved_src, length, changed);
6009#endif
6010 return changed;
6011 }
6012
6013#ifdef DEBUG
6014 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6015 bool expected_changed = false;
6016 for (int i = 0; i < length; i++) {
6017 if (dst[i] == src[i]) continue;
6018 expected_changed = true;
6019 if (dir == ASCII_TO_LOWER) {
6020 ASSERT('A' <= src[i] && src[i] <= 'Z');
6021 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6022 } else {
6023 ASSERT(dir == ASCII_TO_UPPER);
6024 ASSERT('a' <= src[i] && src[i] <= 'z');
6025 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6026 }
6027 }
6028 ASSERT(expected_changed == changed);
6029 }
6030#endif
6031};
6032
6033
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006034struct ToLowerTraits {
6035 typedef unibrow::ToLowercase UnibrowConverter;
6036
lrn@chromium.org303ada72010-10-27 09:33:13 +00006037 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006038};
6039
6040
6041struct ToUpperTraits {
6042 typedef unibrow::ToUppercase UnibrowConverter;
6043
lrn@chromium.org303ada72010-10-27 09:33:13 +00006044 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006045};
6046
6047} // namespace
6048
6049
6050template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006051MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006053 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006054 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006055 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006056 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006057 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006058
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006059 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006060 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006061 if (length == 0) return s;
6062
6063 // Simpler handling of ascii strings.
6064 //
6065 // NOTE: This assumes that the upper/lower case of an ascii
6066 // character is also ascii. This is currently the case, but it
6067 // might break in the future if we implement more context and locale
6068 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006069 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006070 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006071 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006072 if (!maybe_o->ToObject(&o)) return maybe_o;
6073 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006074 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006075 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006076 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006077 return has_changed_character ? result : s;
6078 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006079
lrn@chromium.org303ada72010-10-27 09:33:13 +00006080 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006081 { MaybeObject* maybe_answer =
6082 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006083 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6084 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006085 if (answer->IsSmi()) {
6086 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006087 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 ConvertCaseHelper(isolate,
6089 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006090 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6091 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006092 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006093 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006094}
6095
6096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006097RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006098 return ConvertCase<ToLowerTraits>(
6099 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006100}
6101
6102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006103RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006104 return ConvertCase<ToUpperTraits>(
6105 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006106}
6107
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006108
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006109static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
6110 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
6111}
6112
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006114RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006115 NoHandleAllocation ha;
6116 ASSERT(args.length() == 3);
6117
6118 CONVERT_CHECKED(String, s, args[0]);
6119 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6120 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6121
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006122 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006123 int length = s->length();
6124
6125 int left = 0;
6126 if (trimLeft) {
6127 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6128 left++;
6129 }
6130 }
6131
6132 int right = length;
6133 if (trimRight) {
6134 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6135 right--;
6136 }
6137 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006138 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006139}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006142RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006143 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006144 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006145 CONVERT_ARG_CHECKED(String, subject, 0);
6146 CONVERT_ARG_CHECKED(String, pattern, 1);
6147 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6148
6149 int subject_length = subject->length();
6150 int pattern_length = pattern->length();
6151 RUNTIME_ASSERT(pattern_length > 0);
6152
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006153 if (limit == 0xffffffffu) {
6154 Handle<Object> cached_answer(StringSplitCache::Lookup(
6155 isolate->heap()->string_split_cache(),
6156 *subject,
6157 *pattern));
6158 if (*cached_answer != Smi::FromInt(0)) {
6159 Handle<JSArray> result =
6160 isolate->factory()->NewJSArrayWithElements(
6161 Handle<FixedArray>::cast(cached_answer));
6162 return *result;
6163 }
6164 }
6165
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006166 // The limit can be very large (0xffffffffu), but since the pattern
6167 // isn't empty, we can never create more parts than ~half the length
6168 // of the subject.
6169
6170 if (!subject->IsFlat()) FlattenString(subject);
6171
6172 static const int kMaxInitialListCapacity = 16;
6173
danno@chromium.org40cb8782011-05-25 07:58:50 +00006174 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006175
6176 // Find (up to limit) indices of separator and end-of-string in subject
6177 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6178 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006179 if (!pattern->IsFlat()) FlattenString(pattern);
6180
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006181 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006182
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006183 if (static_cast<uint32_t>(indices.length()) < limit) {
6184 indices.Add(subject_length);
6185 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006186
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006187 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006188
6189 // Create JSArray of substrings separated by separator.
6190 int part_count = indices.length();
6191
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006193 result->set_length(Smi::FromInt(part_count));
6194
6195 ASSERT(result->HasFastElements());
6196
6197 if (part_count == 1 && indices.at(0) == subject_length) {
6198 FixedArray::cast(result->elements())->set(0, *subject);
6199 return *result;
6200 }
6201
6202 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6203 int part_start = 0;
6204 for (int i = 0; i < part_count; i++) {
6205 HandleScope local_loop_handle;
6206 int part_end = indices.at(i);
6207 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006208 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006209 elements->set(i, *substring);
6210 part_start = part_end + pattern_length;
6211 }
6212
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006213 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006214 if (result->HasFastElements()) {
6215 StringSplitCache::Enter(isolate->heap(),
6216 isolate->heap()->string_split_cache(),
6217 *subject,
6218 *pattern,
6219 *elements);
6220 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006221 }
6222
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006223 return *result;
6224}
6225
6226
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006227// Copies ascii characters to the given fixed array looking up
6228// one-char strings in the cache. Gives up on the first char that is
6229// not in the cache and fills the remainder with smi zeros. Returns
6230// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006231static int CopyCachedAsciiCharsToArray(Heap* heap,
6232 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006233 FixedArray* elements,
6234 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006235 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 FixedArray* ascii_cache = heap->single_character_string_cache();
6237 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006238 int i;
6239 for (i = 0; i < length; ++i) {
6240 Object* value = ascii_cache->get(chars[i]);
6241 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006243 elements->set(i, value, SKIP_WRITE_BARRIER);
6244 }
6245 if (i < length) {
6246 ASSERT(Smi::FromInt(0) == 0);
6247 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6248 }
6249#ifdef DEBUG
6250 for (int j = 0; j < length; ++j) {
6251 Object* element = elements->get(j);
6252 ASSERT(element == Smi::FromInt(0) ||
6253 (element->IsString() && String::cast(element)->LooksValid()));
6254 }
6255#endif
6256 return i;
6257}
6258
6259
6260// Converts a String to JSArray.
6261// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006262RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006263 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006264 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006265 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006266 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006267
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006268 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006269 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006270
6271 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006272 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006273 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006274 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006275 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006276 { MaybeObject* maybe_obj =
6277 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006278 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6279 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006280 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006281 String::FlatContent content = s->GetFlatContent();
6282 if (content.IsAscii()) {
6283 Vector<const char> chars = content.ToAsciiVector();
6284 // Note, this will initialize all elements (not only the prefix)
6285 // to prevent GC from seeing partially initialized array.
6286 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6287 chars.start(),
6288 *elements,
6289 length);
6290 } else {
6291 MemsetPointer(elements->data_start(),
6292 isolate->heap()->undefined_value(),
6293 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006294 }
6295 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006296 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006297 }
6298 for (int i = position; i < length; ++i) {
6299 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6300 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006301 }
6302
6303#ifdef DEBUG
6304 for (int i = 0; i < length; ++i) {
6305 ASSERT(String::cast(elements->get(i))->length() == 1);
6306 }
6307#endif
6308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006309 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006310}
6311
6312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006313RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006314 NoHandleAllocation ha;
6315 ASSERT(args.length() == 1);
6316 CONVERT_CHECKED(String, value, args[0]);
6317 return value->ToObject();
6318}
6319
6320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006321bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006322 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006323 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006324 return char_length == 0;
6325}
6326
6327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006328RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329 NoHandleAllocation ha;
6330 ASSERT(args.length() == 1);
6331
6332 Object* number = args[0];
6333 RUNTIME_ASSERT(number->IsNumber());
6334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006336}
6337
6338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006339RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006340 NoHandleAllocation ha;
6341 ASSERT(args.length() == 1);
6342
6343 Object* number = args[0];
6344 RUNTIME_ASSERT(number->IsNumber());
6345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006346 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006347}
6348
6349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006350RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006351 NoHandleAllocation ha;
6352 ASSERT(args.length() == 1);
6353
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006354 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006355
6356 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6357 if (number > 0 && number <= Smi::kMaxValue) {
6358 return Smi::FromInt(static_cast<int>(number));
6359 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006361}
6362
6363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006364RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006365 NoHandleAllocation ha;
6366 ASSERT(args.length() == 1);
6367
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006368 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006369
6370 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6371 if (number > 0 && number <= Smi::kMaxValue) {
6372 return Smi::FromInt(static_cast<int>(number));
6373 }
6374
6375 double double_value = DoubleToInteger(number);
6376 // Map both -0 and +0 to +0.
6377 if (double_value == 0) double_value = 0;
6378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006379 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006380}
6381
6382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006383RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006384 NoHandleAllocation ha;
6385 ASSERT(args.length() == 1);
6386
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006387 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006388 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389}
6390
6391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006392RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006393 NoHandleAllocation ha;
6394 ASSERT(args.length() == 1);
6395
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006396 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397
6398 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6399 if (number > 0 && number <= Smi::kMaxValue) {
6400 return Smi::FromInt(static_cast<int>(number));
6401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006402 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403}
6404
6405
ager@chromium.org870a0b62008-11-04 11:43:05 +00006406// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6407// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006408RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006409 NoHandleAllocation ha;
6410 ASSERT(args.length() == 1);
6411
6412 Object* obj = args[0];
6413 if (obj->IsSmi()) {
6414 return obj;
6415 }
6416 if (obj->IsHeapNumber()) {
6417 double value = HeapNumber::cast(obj)->value();
6418 int int_value = FastD2I(value);
6419 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6420 return Smi::FromInt(int_value);
6421 }
6422 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006423 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006424}
6425
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006427RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006428 NoHandleAllocation ha;
6429 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006431}
6432
6433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006434RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435 NoHandleAllocation ha;
6436 ASSERT(args.length() == 2);
6437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006438 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6439 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441}
6442
6443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006444RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006445 NoHandleAllocation ha;
6446 ASSERT(args.length() == 2);
6447
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006448 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6449 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006450 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451}
6452
6453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006454RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006455 NoHandleAllocation ha;
6456 ASSERT(args.length() == 2);
6457
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006458 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6459 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006461}
6462
6463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006464RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006465 NoHandleAllocation ha;
6466 ASSERT(args.length() == 1);
6467
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006468 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006469 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006470}
6471
6472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006473RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006474 NoHandleAllocation ha;
6475 ASSERT(args.length() == 0);
6476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006478}
6479
6480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006481RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482 NoHandleAllocation ha;
6483 ASSERT(args.length() == 2);
6484
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006485 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6486 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006487 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488}
6489
6490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006491RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 2);
6494
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006495 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6496 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497
ager@chromium.org3811b432009-10-28 14:53:37 +00006498 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006499 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006500 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006501}
6502
6503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006504RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 NoHandleAllocation ha;
6506 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006507 CONVERT_CHECKED(String, str1, args[0]);
6508 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 isolate->counters()->string_add_runtime()->Increment();
6510 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006511}
6512
6513
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006514template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006515static inline void StringBuilderConcatHelper(String* special,
6516 sinkchar* sink,
6517 FixedArray* fixed_array,
6518 int array_length) {
6519 int position = 0;
6520 for (int i = 0; i < array_length; i++) {
6521 Object* element = fixed_array->get(i);
6522 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006523 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006524 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006525 int pos;
6526 int len;
6527 if (encoded_slice > 0) {
6528 // Position and length encoded in one smi.
6529 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6530 len = StringBuilderSubstringLength::decode(encoded_slice);
6531 } else {
6532 // Position and length encoded in two smis.
6533 Object* obj = fixed_array->get(++i);
6534 ASSERT(obj->IsSmi());
6535 pos = Smi::cast(obj)->value();
6536 len = -encoded_slice;
6537 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006538 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006539 sink + position,
6540 pos,
6541 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006542 position += len;
6543 } else {
6544 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006545 int element_length = string->length();
6546 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006547 position += element_length;
6548 }
6549 }
6550}
6551
6552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006553RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006555 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006556 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006557 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006558 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006559 return Failure::OutOfMemoryException();
6560 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006561 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006562 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006563
6564 // This assumption is used by the slice encoding in one or two smis.
6565 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6566
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006567 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006569 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570 }
6571 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006572 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575
6576 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006577 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578 } else if (array_length == 1) {
6579 Object* first = fixed_array->get(0);
6580 if (first->IsString()) return first;
6581 }
6582
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006583 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 int position = 0;
6585 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006586 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 Object* elt = fixed_array->get(i);
6588 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006589 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006590 int smi_value = Smi::cast(elt)->value();
6591 int pos;
6592 int len;
6593 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006594 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006595 pos = StringBuilderSubstringPosition::decode(smi_value);
6596 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006597 } else {
6598 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006599 len = -smi_value;
6600 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006601 i++;
6602 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006603 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006604 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006605 Object* next_smi = fixed_array->get(i);
6606 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006608 }
6609 pos = Smi::cast(next_smi)->value();
6610 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006614 ASSERT(pos >= 0);
6615 ASSERT(len >= 0);
6616 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006617 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006618 }
6619 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 } else if (elt->IsString()) {
6621 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006622 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006623 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006624 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006630 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006631 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006632 return Failure::OutOfMemoryException();
6633 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006634 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635 }
6636
6637 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006639
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 { MaybeObject* maybe_object =
6642 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006643 if (!maybe_object->ToObject(&object)) return maybe_object;
6644 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006645 SeqAsciiString* answer = SeqAsciiString::cast(object);
6646 StringBuilderConcatHelper(special,
6647 answer->GetChars(),
6648 fixed_array,
6649 array_length);
6650 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006651 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006652 { MaybeObject* maybe_object =
6653 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006654 if (!maybe_object->ToObject(&object)) return maybe_object;
6655 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006656 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6657 StringBuilderConcatHelper(special,
6658 answer->GetChars(),
6659 fixed_array,
6660 array_length);
6661 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006663}
6664
6665
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006666RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006667 NoHandleAllocation ha;
6668 ASSERT(args.length() == 3);
6669 CONVERT_CHECKED(JSArray, array, args[0]);
6670 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006672 return Failure::OutOfMemoryException();
6673 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006674 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006675 CONVERT_CHECKED(String, separator, args[2]);
6676
6677 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006678 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006679 }
6680 FixedArray* fixed_array = FixedArray::cast(array->elements());
6681 if (fixed_array->length() < array_length) {
6682 array_length = fixed_array->length();
6683 }
6684
6685 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006687 } else if (array_length == 1) {
6688 Object* first = fixed_array->get(0);
6689 if (first->IsString()) return first;
6690 }
6691
6692 int separator_length = separator->length();
6693 int max_nof_separators =
6694 (String::kMaxLength + separator_length - 1) / separator_length;
6695 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006696 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006697 return Failure::OutOfMemoryException();
6698 }
6699 int length = (array_length - 1) * separator_length;
6700 for (int i = 0; i < array_length; i++) {
6701 Object* element_obj = fixed_array->get(i);
6702 if (!element_obj->IsString()) {
6703 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006705 }
6706 String* element = String::cast(element_obj);
6707 int increment = element->length();
6708 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006709 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006710 return Failure::OutOfMemoryException();
6711 }
6712 length += increment;
6713 }
6714
6715 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006716 { MaybeObject* maybe_object =
6717 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006718 if (!maybe_object->ToObject(&object)) return maybe_object;
6719 }
6720 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6721
6722 uc16* sink = answer->GetChars();
6723#ifdef DEBUG
6724 uc16* end = sink + length;
6725#endif
6726
6727 String* first = String::cast(fixed_array->get(0));
6728 int first_length = first->length();
6729 String::WriteToFlat(first, sink, 0, first_length);
6730 sink += first_length;
6731
6732 for (int i = 1; i < array_length; i++) {
6733 ASSERT(sink + separator_length <= end);
6734 String::WriteToFlat(separator, sink, 0, separator_length);
6735 sink += separator_length;
6736
6737 String* element = String::cast(fixed_array->get(i));
6738 int element_length = element->length();
6739 ASSERT(sink + element_length <= end);
6740 String::WriteToFlat(element, sink, 0, element_length);
6741 sink += element_length;
6742 }
6743 ASSERT(sink == end);
6744
6745 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6746 return answer;
6747}
6748
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006749template <typename Char>
6750static void JoinSparseArrayWithSeparator(FixedArray* elements,
6751 int elements_length,
6752 uint32_t array_length,
6753 String* separator,
6754 Vector<Char> buffer) {
6755 int previous_separator_position = 0;
6756 int separator_length = separator->length();
6757 int cursor = 0;
6758 for (int i = 0; i < elements_length; i += 2) {
6759 int position = NumberToInt32(elements->get(i));
6760 String* string = String::cast(elements->get(i + 1));
6761 int string_length = string->length();
6762 if (string->length() > 0) {
6763 while (previous_separator_position < position) {
6764 String::WriteToFlat<Char>(separator, &buffer[cursor],
6765 0, separator_length);
6766 cursor += separator_length;
6767 previous_separator_position++;
6768 }
6769 String::WriteToFlat<Char>(string, &buffer[cursor],
6770 0, string_length);
6771 cursor += string->length();
6772 }
6773 }
6774 if (separator_length > 0) {
6775 // Array length must be representable as a signed 32-bit number,
6776 // otherwise the total string length would have been too large.
6777 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6778 int last_array_index = static_cast<int>(array_length - 1);
6779 while (previous_separator_position < last_array_index) {
6780 String::WriteToFlat<Char>(separator, &buffer[cursor],
6781 0, separator_length);
6782 cursor += separator_length;
6783 previous_separator_position++;
6784 }
6785 }
6786 ASSERT(cursor <= buffer.length());
6787}
6788
6789
6790RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6791 NoHandleAllocation ha;
6792 ASSERT(args.length() == 3);
6793 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6794 RUNTIME_ASSERT(elements_array->HasFastElements());
6795 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6796 CONVERT_CHECKED(String, separator, args[2]);
6797 // elements_array is fast-mode JSarray of alternating positions
6798 // (increasing order) and strings.
6799 // array_length is length of original array (used to add separators);
6800 // separator is string to put between elements. Assumed to be non-empty.
6801
6802 // Find total length of join result.
6803 int string_length = 0;
6804 bool is_ascii = true;
6805 int max_string_length = SeqAsciiString::kMaxLength;
6806 bool overflow = false;
6807 CONVERT_NUMBER_CHECKED(int, elements_length,
6808 Int32, elements_array->length());
6809 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6810 FixedArray* elements = FixedArray::cast(elements_array->elements());
6811 for (int i = 0; i < elements_length; i += 2) {
6812 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6813 CONVERT_CHECKED(String, string, elements->get(i + 1));
6814 int length = string->length();
6815 if (is_ascii && !string->IsAsciiRepresentation()) {
6816 is_ascii = false;
6817 max_string_length = SeqTwoByteString::kMaxLength;
6818 }
6819 if (length > max_string_length ||
6820 max_string_length - length < string_length) {
6821 overflow = true;
6822 break;
6823 }
6824 string_length += length;
6825 }
6826 int separator_length = separator->length();
6827 if (!overflow && separator_length > 0) {
6828 if (array_length <= 0x7fffffffu) {
6829 int separator_count = static_cast<int>(array_length) - 1;
6830 int remaining_length = max_string_length - string_length;
6831 if ((remaining_length / separator_length) >= separator_count) {
6832 string_length += separator_length * (array_length - 1);
6833 } else {
6834 // Not room for the separators within the maximal string length.
6835 overflow = true;
6836 }
6837 } else {
6838 // Nonempty separator and at least 2^31-1 separators necessary
6839 // means that the string is too large to create.
6840 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6841 overflow = true;
6842 }
6843 }
6844 if (overflow) {
6845 // Throw OutOfMemory exception for creating too large a string.
6846 V8::FatalProcessOutOfMemory("Array join result too large.");
6847 }
6848
6849 if (is_ascii) {
6850 MaybeObject* result_allocation =
6851 isolate->heap()->AllocateRawAsciiString(string_length);
6852 if (result_allocation->IsFailure()) return result_allocation;
6853 SeqAsciiString* result_string =
6854 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6855 JoinSparseArrayWithSeparator<char>(elements,
6856 elements_length,
6857 array_length,
6858 separator,
6859 Vector<char>(result_string->GetChars(),
6860 string_length));
6861 return result_string;
6862 } else {
6863 MaybeObject* result_allocation =
6864 isolate->heap()->AllocateRawTwoByteString(string_length);
6865 if (result_allocation->IsFailure()) return result_allocation;
6866 SeqTwoByteString* result_string =
6867 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6868 JoinSparseArrayWithSeparator<uc16>(elements,
6869 elements_length,
6870 array_length,
6871 separator,
6872 Vector<uc16>(result_string->GetChars(),
6873 string_length));
6874 return result_string;
6875 }
6876}
6877
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006879RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880 NoHandleAllocation ha;
6881 ASSERT(args.length() == 2);
6882
6883 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6884 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006885 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886}
6887
6888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006889RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890 NoHandleAllocation ha;
6891 ASSERT(args.length() == 2);
6892
6893 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6894 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006895 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006896}
6897
6898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006899RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006900 NoHandleAllocation ha;
6901 ASSERT(args.length() == 2);
6902
6903 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6904 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006905 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006906}
6907
6908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006909RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006910 NoHandleAllocation ha;
6911 ASSERT(args.length() == 1);
6912
6913 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006914 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915}
6916
6917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006918RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 2);
6921
6922 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6923 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006924 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006925}
6926
6927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006928RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929 NoHandleAllocation ha;
6930 ASSERT(args.length() == 2);
6931
6932 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6933 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006934 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935}
6936
6937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006938RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939 NoHandleAllocation ha;
6940 ASSERT(args.length() == 2);
6941
6942 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6943 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006944 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006945}
6946
6947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006948RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949 NoHandleAllocation ha;
6950 ASSERT(args.length() == 2);
6951
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006952 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6953 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006954 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6955 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6956 if (x == y) return Smi::FromInt(EQUAL);
6957 Object* result;
6958 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6959 result = Smi::FromInt(EQUAL);
6960 } else {
6961 result = Smi::FromInt(NOT_EQUAL);
6962 }
6963 return result;
6964}
6965
6966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006968 NoHandleAllocation ha;
6969 ASSERT(args.length() == 2);
6970
6971 CONVERT_CHECKED(String, x, args[0]);
6972 CONVERT_CHECKED(String, y, args[1]);
6973
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006974 bool not_equal = !x->Equals(y);
6975 // This is slightly convoluted because the value that signifies
6976 // equality is 0 and inequality is 1 so we have to negate the result
6977 // from String::Equals.
6978 ASSERT(not_equal == 0 || not_equal == 1);
6979 STATIC_CHECK(EQUAL == 0);
6980 STATIC_CHECK(NOT_EQUAL == 1);
6981 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982}
6983
6984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006985RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 NoHandleAllocation ha;
6987 ASSERT(args.length() == 3);
6988
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006989 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6990 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991 if (isnan(x) || isnan(y)) return args[2];
6992 if (x == y) return Smi::FromInt(EQUAL);
6993 if (isless(x, y)) return Smi::FromInt(LESS);
6994 return Smi::FromInt(GREATER);
6995}
6996
6997
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006998// Compare two Smis as if they were converted to strings and then
6999// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007000RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007001 NoHandleAllocation ha;
7002 ASSERT(args.length() == 2);
7003
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007004 // Extract the integer values from the Smis.
7005 CONVERT_CHECKED(Smi, x, args[0]);
7006 CONVERT_CHECKED(Smi, y, args[1]);
7007 int x_value = x->value();
7008 int y_value = y->value();
7009
7010 // If the integers are equal so are the string representations.
7011 if (x_value == y_value) return Smi::FromInt(EQUAL);
7012
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007013 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007014 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007015 if (x_value == 0 || y_value == 0)
7016 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007017
ager@chromium.org32912102009-01-16 10:38:43 +00007018 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007019 // smallest because the char code of '-' is less than the char code
7020 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007021
7022 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7023 // architectures using 32-bit Smis.
7024 uint32_t x_scaled = x_value;
7025 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007026 if (x_value < 0 || y_value < 0) {
7027 if (y_value >= 0) return Smi::FromInt(LESS);
7028 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007029 x_scaled = -x_value;
7030 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007031 }
7032
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007033 static const uint32_t kPowersOf10[] = {
7034 1, 10, 100, 1000, 10*1000, 100*1000,
7035 1000*1000, 10*1000*1000, 100*1000*1000,
7036 1000*1000*1000
7037 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007038
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007039 // If the integers have the same number of decimal digits they can be
7040 // compared directly as the numeric order is the same as the
7041 // lexicographic order. If one integer has fewer digits, it is scaled
7042 // by some power of 10 to have the same number of digits as the longer
7043 // integer. If the scaled integers are equal it means the shorter
7044 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007045
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007046 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7047 int x_log2 = IntegerLog2(x_scaled);
7048 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7049 x_log10 -= x_scaled < kPowersOf10[x_log10];
7050
7051 int y_log2 = IntegerLog2(y_scaled);
7052 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7053 y_log10 -= y_scaled < kPowersOf10[y_log10];
7054
7055 int tie = EQUAL;
7056
7057 if (x_log10 < y_log10) {
7058 // X has fewer digits. We would like to simply scale up X but that
7059 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7060 // be scaled up to 9_000_000_000. So we scale up by the next
7061 // smallest power and scale down Y to drop one digit. It is OK to
7062 // drop one digit from the longer integer since the final digit is
7063 // past the length of the shorter integer.
7064 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7065 y_scaled /= 10;
7066 tie = LESS;
7067 } else if (y_log10 < x_log10) {
7068 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7069 x_scaled /= 10;
7070 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007071 }
7072
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007073 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7074 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7075 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007076}
7077
7078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007079static Object* StringInputBufferCompare(RuntimeState* state,
7080 String* x,
7081 String* y) {
7082 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7083 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007084 bufx.Reset(x);
7085 bufy.Reset(y);
7086 while (bufx.has_more() && bufy.has_more()) {
7087 int d = bufx.GetNext() - bufy.GetNext();
7088 if (d < 0) return Smi::FromInt(LESS);
7089 else if (d > 0) return Smi::FromInt(GREATER);
7090 }
7091
7092 // x is (non-trivial) prefix of y:
7093 if (bufy.has_more()) return Smi::FromInt(LESS);
7094 // y is prefix of x:
7095 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7096}
7097
7098
7099static Object* FlatStringCompare(String* x, String* y) {
7100 ASSERT(x->IsFlat());
7101 ASSERT(y->IsFlat());
7102 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7103 int prefix_length = x->length();
7104 if (y->length() < prefix_length) {
7105 prefix_length = y->length();
7106 equal_prefix_result = Smi::FromInt(GREATER);
7107 } else if (y->length() > prefix_length) {
7108 equal_prefix_result = Smi::FromInt(LESS);
7109 }
7110 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007111 String::FlatContent x_content = x->GetFlatContent();
7112 String::FlatContent y_content = y->GetFlatContent();
7113 if (x_content.IsAscii()) {
7114 Vector<const char> x_chars = x_content.ToAsciiVector();
7115 if (y_content.IsAscii()) {
7116 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007117 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007118 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007119 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007120 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7121 }
7122 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007123 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7124 if (y_content.IsAscii()) {
7125 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007126 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7127 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007128 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007129 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7130 }
7131 }
7132 Object* result;
7133 if (r == 0) {
7134 result = equal_prefix_result;
7135 } else {
7136 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7137 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007138 ASSERT(result ==
7139 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007140 return result;
7141}
7142
7143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007144RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007145 NoHandleAllocation ha;
7146 ASSERT(args.length() == 2);
7147
7148 CONVERT_CHECKED(String, x, args[0]);
7149 CONVERT_CHECKED(String, y, args[1]);
7150
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007151 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007153 // A few fast case tests before we flatten.
7154 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007155 if (y->length() == 0) {
7156 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007157 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007158 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007159 return Smi::FromInt(LESS);
7160 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007161
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007162 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007163 if (d < 0) return Smi::FromInt(LESS);
7164 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007165
lrn@chromium.org303ada72010-10-27 09:33:13 +00007166 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007167 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007168 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7169 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007170 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007171 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7172 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007174 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007175 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007176}
7177
7178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007179RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007180 NoHandleAllocation ha;
7181 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007182 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007184 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007186}
7187
7188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007189RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007190 NoHandleAllocation ha;
7191 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007192 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007193
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007194 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007195 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196}
7197
7198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007199RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007200 NoHandleAllocation ha;
7201 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007202 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007203
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007204 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007205 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007206}
7207
7208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007209static const double kPiDividedBy4 = 0.78539816339744830962;
7210
7211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007212RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007213 NoHandleAllocation ha;
7214 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007215 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007216
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007217 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7218 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007219 double result;
7220 if (isinf(x) && isinf(y)) {
7221 // Make sure that the result in case of two infinite arguments
7222 // is a multiple of Pi / 4. The sign of the result is determined
7223 // by the first argument (x) and the sign of the second argument
7224 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007225 int multiplier = (x < 0) ? -1 : 1;
7226 if (y < 0) multiplier *= 3;
7227 result = multiplier * kPiDividedBy4;
7228 } else {
7229 result = atan2(x, y);
7230 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007231 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007232}
7233
7234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007235RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007236 NoHandleAllocation ha;
7237 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007238 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007240 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007241 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007242}
7243
7244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007245RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007246 NoHandleAllocation ha;
7247 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007248 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007249
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007250 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007251 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007252}
7253
7254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007255RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007256 NoHandleAllocation ha;
7257 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007258 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007259
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007260 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007261 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007262}
7263
7264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007265RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266 NoHandleAllocation ha;
7267 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007268 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007269
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007270 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007271 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272}
7273
7274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007275RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 NoHandleAllocation ha;
7277 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007278 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007279
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007280 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007281 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007282}
7283
7284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007285RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286 NoHandleAllocation ha;
7287 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007290 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007291
7292 // If the second argument is a smi, it is much faster to call the
7293 // custom powi() function than the generic pow().
7294 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007295 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007296 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007297 }
7298
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007299 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007300 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301}
7302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007303// Fast version of Math.pow if we know that y is not an integer and
7304// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007305RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007306 NoHandleAllocation ha;
7307 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007308 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7309 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007310 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007311 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007312 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007314 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007316 }
7317}
7318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007320RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 NoHandleAllocation ha;
7322 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007325 if (!args[0]->IsHeapNumber()) {
7326 // Must be smi. Return the argument unchanged for all the other types
7327 // to make fuzz-natives test happy.
7328 return args[0];
7329 }
7330
7331 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7332
7333 double value = number->value();
7334 int exponent = number->get_exponent();
7335 int sign = number->get_sign();
7336
danno@chromium.org160a7b02011-04-18 15:51:38 +00007337 if (exponent < -1) {
7338 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7339 if (sign) return isolate->heap()->minus_zero_value();
7340 return Smi::FromInt(0);
7341 }
7342
7343 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7344 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7345 // agument holds for 32-bit smis).
7346 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007347 return Smi::FromInt(static_cast<int>(value + 0.5));
7348 }
7349
7350 // If the magnitude is big enough, there's no place for fraction part. If we
7351 // try to add 0.5 to this number, 1.0 will be added instead.
7352 if (exponent >= 52) {
7353 return number;
7354 }
7355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007357
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007358 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360}
7361
7362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007363RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364 NoHandleAllocation ha;
7365 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007368 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370}
7371
7372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007373RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380}
7381
7382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007383RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 NoHandleAllocation ha;
7385 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007388 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390}
7391
7392
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007393static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007394 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7395 181, 212, 243, 273, 304, 334};
7396 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7397 182, 213, 244, 274, 305, 335};
7398
7399 year += month / 12;
7400 month %= 12;
7401 if (month < 0) {
7402 year--;
7403 month += 12;
7404 }
7405
7406 ASSERT(month >= 0);
7407 ASSERT(month < 12);
7408
7409 // year_delta is an arbitrary number such that:
7410 // a) year_delta = -1 (mod 400)
7411 // b) year + year_delta > 0 for years in the range defined by
7412 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7413 // Jan 1 1970. This is required so that we don't run into integer
7414 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007415 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007416 // operations.
7417 static const int year_delta = 399999;
7418 static const int base_day = 365 * (1970 + year_delta) +
7419 (1970 + year_delta) / 4 -
7420 (1970 + year_delta) / 100 +
7421 (1970 + year_delta) / 400;
7422
7423 int year1 = year + year_delta;
7424 int day_from_year = 365 * year1 +
7425 year1 / 4 -
7426 year1 / 100 +
7427 year1 / 400 -
7428 base_day;
7429
7430 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007431 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007432 }
7433
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007434 return day_from_year + day_from_month_leap[month] + day - 1;
7435}
7436
7437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007438RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007439 NoHandleAllocation ha;
7440 ASSERT(args.length() == 3);
7441
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007442 CONVERT_SMI_ARG_CHECKED(year, 0);
7443 CONVERT_SMI_ARG_CHECKED(month, 1);
7444 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007445
7446 return Smi::FromInt(MakeDay(year, month, date));
7447}
7448
7449
7450static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7451static const int kDaysIn4Years = 4 * 365 + 1;
7452static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7453static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7454static const int kDays1970to2000 = 30 * 365 + 7;
7455static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7456 kDays1970to2000;
7457static const int kYearsOffset = 400000;
7458
7459static const char kDayInYear[] = {
7460 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7461 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7462 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7463 22, 23, 24, 25, 26, 27, 28,
7464 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7465 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7466 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7467 22, 23, 24, 25, 26, 27, 28, 29, 30,
7468 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7469 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7470 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7471 22, 23, 24, 25, 26, 27, 28, 29, 30,
7472 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7473 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7474 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7475 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7476 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7477 22, 23, 24, 25, 26, 27, 28, 29, 30,
7478 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7479 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7480 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7481 22, 23, 24, 25, 26, 27, 28, 29, 30,
7482 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7483 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7484
7485 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7486 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7487 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7488 22, 23, 24, 25, 26, 27, 28,
7489 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7490 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7491 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7492 22, 23, 24, 25, 26, 27, 28, 29, 30,
7493 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7494 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7495 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7496 22, 23, 24, 25, 26, 27, 28, 29, 30,
7497 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7498 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7499 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7500 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7501 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7502 22, 23, 24, 25, 26, 27, 28, 29, 30,
7503 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7504 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7505 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7506 22, 23, 24, 25, 26, 27, 28, 29, 30,
7507 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7508 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7509
7510 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7511 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7512 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7513 22, 23, 24, 25, 26, 27, 28, 29,
7514 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7515 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7516 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7517 22, 23, 24, 25, 26, 27, 28, 29, 30,
7518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7519 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7520 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7521 22, 23, 24, 25, 26, 27, 28, 29, 30,
7522 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7523 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7524 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7525 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7526 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7527 22, 23, 24, 25, 26, 27, 28, 29, 30,
7528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7529 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7531 22, 23, 24, 25, 26, 27, 28, 29, 30,
7532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7533 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7534
7535 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7536 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7537 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7538 22, 23, 24, 25, 26, 27, 28,
7539 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7540 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7542 22, 23, 24, 25, 26, 27, 28, 29, 30,
7543 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7544 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7545 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7546 22, 23, 24, 25, 26, 27, 28, 29, 30,
7547 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7548 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7549 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7550 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7551 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7552 22, 23, 24, 25, 26, 27, 28, 29, 30,
7553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7554 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7556 22, 23, 24, 25, 26, 27, 28, 29, 30,
7557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7558 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7559
7560static const char kMonthInYear[] = {
7561 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7562 0, 0, 0, 0, 0, 0,
7563 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7564 1, 1, 1,
7565 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7566 2, 2, 2, 2, 2, 2,
7567 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7568 3, 3, 3, 3, 3,
7569 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7570 4, 4, 4, 4, 4, 4,
7571 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7572 5, 5, 5, 5, 5,
7573 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7574 6, 6, 6, 6, 6, 6,
7575 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7576 7, 7, 7, 7, 7, 7,
7577 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7578 8, 8, 8, 8, 8,
7579 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7580 9, 9, 9, 9, 9, 9,
7581 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7582 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7583 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7584 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7585
7586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7587 0, 0, 0, 0, 0, 0,
7588 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7589 1, 1, 1,
7590 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7591 2, 2, 2, 2, 2, 2,
7592 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7593 3, 3, 3, 3, 3,
7594 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7595 4, 4, 4, 4, 4, 4,
7596 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7597 5, 5, 5, 5, 5,
7598 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7599 6, 6, 6, 6, 6, 6,
7600 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7601 7, 7, 7, 7, 7, 7,
7602 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7603 8, 8, 8, 8, 8,
7604 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7605 9, 9, 9, 9, 9, 9,
7606 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7607 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7608 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7609 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7610
7611 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7612 0, 0, 0, 0, 0, 0,
7613 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7614 1, 1, 1, 1,
7615 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7616 2, 2, 2, 2, 2, 2,
7617 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7618 3, 3, 3, 3, 3,
7619 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7620 4, 4, 4, 4, 4, 4,
7621 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7622 5, 5, 5, 5, 5,
7623 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7624 6, 6, 6, 6, 6, 6,
7625 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7626 7, 7, 7, 7, 7, 7,
7627 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7628 8, 8, 8, 8, 8,
7629 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7630 9, 9, 9, 9, 9, 9,
7631 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7632 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7633 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7634 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7635
7636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7637 0, 0, 0, 0, 0, 0,
7638 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7639 1, 1, 1,
7640 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7641 2, 2, 2, 2, 2, 2,
7642 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7643 3, 3, 3, 3, 3,
7644 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7645 4, 4, 4, 4, 4, 4,
7646 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7647 5, 5, 5, 5, 5,
7648 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7649 6, 6, 6, 6, 6, 6,
7650 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7651 7, 7, 7, 7, 7, 7,
7652 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7653 8, 8, 8, 8, 8,
7654 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7655 9, 9, 9, 9, 9, 9,
7656 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7657 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7658 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7659 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7660
7661
7662// This function works for dates from 1970 to 2099.
7663static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007664 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007665#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007666 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007667#endif
7668
7669 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7670 date %= kDaysIn4Years;
7671
7672 month = kMonthInYear[date];
7673 day = kDayInYear[date];
7674
7675 ASSERT(MakeDay(year, month, day) == save_date);
7676}
7677
7678
7679static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007680 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007681#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007682 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007683#endif
7684
7685 date += kDaysOffset;
7686 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7687 date %= kDaysIn400Years;
7688
7689 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7690
7691 date--;
7692 int yd1 = date / kDaysIn100Years;
7693 date %= kDaysIn100Years;
7694 year += 100 * yd1;
7695
7696 date++;
7697 int yd2 = date / kDaysIn4Years;
7698 date %= kDaysIn4Years;
7699 year += 4 * yd2;
7700
7701 date--;
7702 int yd3 = date / 365;
7703 date %= 365;
7704 year += yd3;
7705
7706 bool is_leap = (!yd1 || yd2) && !yd3;
7707
7708 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007709 ASSERT(is_leap || (date >= 0));
7710 ASSERT((date < 365) || (is_leap && (date < 366)));
7711 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7712 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7713 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007714
7715 if (is_leap) {
7716 day = kDayInYear[2*365 + 1 + date];
7717 month = kMonthInYear[2*365 + 1 + date];
7718 } else {
7719 day = kDayInYear[date];
7720 month = kMonthInYear[date];
7721 }
7722
7723 ASSERT(MakeDay(year, month, day) == save_date);
7724}
7725
7726
7727static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007728 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007729 if (date >= 0 && date < 32 * kDaysIn4Years) {
7730 DateYMDFromTimeAfter1970(date, year, month, day);
7731 } else {
7732 DateYMDFromTimeSlow(date, year, month, day);
7733 }
7734}
7735
7736
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007737RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007738 NoHandleAllocation ha;
7739 ASSERT(args.length() == 2);
7740
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007741 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007742 CONVERT_CHECKED(JSArray, res_array, args[1]);
7743
7744 int year, month, day;
7745 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 RUNTIME_ASSERT(res_array->elements()->map() ==
7748 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007749 FixedArray* elms = FixedArray::cast(res_array->elements());
7750 RUNTIME_ASSERT(elms->length() == 3);
7751
7752 elms->set(0, Smi::FromInt(year));
7753 elms->set(1, Smi::FromInt(month));
7754 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007755
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007756 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007757}
7758
7759
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007760RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007761 HandleScope scope(isolate);
7762 ASSERT(args.length() == 3);
7763
7764 Handle<JSFunction> callee = args.at<JSFunction>(0);
7765 Object** parameters = reinterpret_cast<Object**>(args[1]);
7766 const int argument_count = Smi::cast(args[2])->value();
7767
7768 Handle<JSObject> result =
7769 isolate->factory()->NewArgumentsObject(callee, argument_count);
7770 // Allocate the elements if needed.
7771 int parameter_count = callee->shared()->formal_parameter_count();
7772 if (argument_count > 0) {
7773 if (parameter_count > 0) {
7774 int mapped_count = Min(argument_count, parameter_count);
7775 Handle<FixedArray> parameter_map =
7776 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7777 parameter_map->set_map(
7778 isolate->heap()->non_strict_arguments_elements_map());
7779
7780 Handle<Map> old_map(result->map());
7781 Handle<Map> new_map =
7782 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007783 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007784
7785 result->set_map(*new_map);
7786 result->set_elements(*parameter_map);
7787
7788 // Store the context and the arguments array at the beginning of the
7789 // parameter map.
7790 Handle<Context> context(isolate->context());
7791 Handle<FixedArray> arguments =
7792 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7793 parameter_map->set(0, *context);
7794 parameter_map->set(1, *arguments);
7795
7796 // Loop over the actual parameters backwards.
7797 int index = argument_count - 1;
7798 while (index >= mapped_count) {
7799 // These go directly in the arguments array and have no
7800 // corresponding slot in the parameter map.
7801 arguments->set(index, *(parameters - index - 1));
7802 --index;
7803 }
7804
7805 ScopeInfo<> scope_info(callee->shared()->scope_info());
7806 while (index >= 0) {
7807 // Detect duplicate names to the right in the parameter list.
7808 Handle<String> name = scope_info.parameter_name(index);
7809 int context_slot_count = scope_info.number_of_context_slots();
7810 bool duplicate = false;
7811 for (int j = index + 1; j < parameter_count; ++j) {
7812 if (scope_info.parameter_name(j).is_identical_to(name)) {
7813 duplicate = true;
7814 break;
7815 }
7816 }
7817
7818 if (duplicate) {
7819 // This goes directly in the arguments array with a hole in the
7820 // parameter map.
7821 arguments->set(index, *(parameters - index - 1));
7822 parameter_map->set_the_hole(index + 2);
7823 } else {
7824 // The context index goes in the parameter map with a hole in the
7825 // arguments array.
7826 int context_index = -1;
7827 for (int j = Context::MIN_CONTEXT_SLOTS;
7828 j < context_slot_count;
7829 ++j) {
7830 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7831 context_index = j;
7832 break;
7833 }
7834 }
7835 ASSERT(context_index >= 0);
7836 arguments->set_the_hole(index);
7837 parameter_map->set(index + 2, Smi::FromInt(context_index));
7838 }
7839
7840 --index;
7841 }
7842 } else {
7843 // If there is no aliasing, the arguments object elements are not
7844 // special in any way.
7845 Handle<FixedArray> elements =
7846 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7847 result->set_elements(*elements);
7848 for (int i = 0; i < argument_count; ++i) {
7849 elements->set(i, *(parameters - i - 1));
7850 }
7851 }
7852 }
7853 return *result;
7854}
7855
7856
7857RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007858 NoHandleAllocation ha;
7859 ASSERT(args.length() == 3);
7860
7861 JSFunction* callee = JSFunction::cast(args[0]);
7862 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007863 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007864
lrn@chromium.org303ada72010-10-27 09:33:13 +00007865 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007866 { MaybeObject* maybe_result =
7867 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007868 if (!maybe_result->ToObject(&result)) return maybe_result;
7869 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007870 // Allocate the elements if needed.
7871 if (length > 0) {
7872 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007873 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007874 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007875 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7876 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007877
7878 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007879 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007881 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007882
7883 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007884 for (int i = 0; i < length; i++) {
7885 array->set(i, *--parameters, mode);
7886 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007887 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007888 }
7889 return result;
7890}
7891
7892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007893RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007894 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007895 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007896 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007897 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007898 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899
whesse@chromium.org7b260152011-06-20 15:33:18 +00007900 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007901 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007902 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007903 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007904 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7905 context,
7906 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007907 return *result;
7908}
7909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007910
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007911static SmartArrayPointer<Object**> GetNonBoundArguments(int bound_argc,
7912 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007913 // Find frame containing arguments passed to the caller.
7914 JavaScriptFrameIterator it;
7915 JavaScriptFrame* frame = it.frame();
7916 List<JSFunction*> functions(2);
7917 frame->GetFunctions(&functions);
7918 if (functions.length() > 1) {
7919 int inlined_frame_index = functions.length() - 1;
7920 JSFunction* inlined_function = functions[inlined_frame_index];
7921 int args_count = inlined_function->shared()->formal_parameter_count();
7922 ScopedVector<SlotRef> args_slots(args_count);
7923 SlotRef::ComputeSlotMappingForArguments(frame,
7924 inlined_frame_index,
7925 &args_slots);
7926
7927 *total_argc = bound_argc + args_count;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007928 SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007929 for (int i = 0; i < args_count; i++) {
7930 Handle<Object> val = args_slots[i].GetValue();
7931 param_data[bound_argc + i] = val.location();
7932 }
7933 return param_data;
7934 } else {
7935 it.AdvanceToArgumentsFrame();
7936 frame = it.frame();
7937 int args_count = frame->ComputeParametersCount();
7938
7939 *total_argc = bound_argc + args_count;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007940 SmartArrayPointer<Object**> param_data(NewArray<Object**>(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007941 for (int i = 0; i < args_count; i++) {
7942 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7943 param_data[bound_argc + i] = val.location();
7944 }
7945 return param_data;
7946 }
7947}
7948
7949
7950RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007951 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007952 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007953 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007954 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007955
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007956 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007957 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007958 int bound_argc = 0;
7959 if (!args[1]->IsNull()) {
7960 CONVERT_ARG_CHECKED(JSArray, params, 1);
7961 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007962 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007963 bound_argc = Smi::cast(params->length())->value();
7964 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007966 int total_argc = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007967 SmartArrayPointer<Object**> param_data =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007968 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007969 for (int i = 0; i < bound_argc; i++) {
7970 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007971 param_data[i] = val.location();
7972 }
7973
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007974 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007975 Handle<Object> result =
7976 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007977 if (exception) {
7978 return Failure::Exception();
7979 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007980
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007981 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007982 return *result;
7983}
7984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007986static void TrySettingInlineConstructStub(Isolate* isolate,
7987 Handle<JSFunction> function) {
7988 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007989 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007990 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007991 }
7992 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007993 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007994 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007995 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007996 function->shared()->set_construct_stub(
7997 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007998 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007999 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008000}
8001
8002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008003RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008004 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005 ASSERT(args.length() == 1);
8006
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008007 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008008
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008009 // If the constructor isn't a proper function we throw a type error.
8010 if (!constructor->IsJSFunction()) {
8011 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8012 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008013 isolate->factory()->NewTypeError("not_constructor", arguments);
8014 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008015 }
8016
8017 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008018
8019 // If function should not have prototype, construction is not allowed. In this
8020 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008021 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008022 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8023 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008024 isolate->factory()->NewTypeError("not_constructor", arguments);
8025 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008026 }
8027
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008028#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008029 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008030 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008031 if (debug->StepInActive()) {
8032 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008033 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008034#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008036 if (function->has_initial_map()) {
8037 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008038 // The 'Function' function ignores the receiver object when
8039 // called using 'new' and creates a new JSFunction object that
8040 // is returned. The receiver object is only used for error
8041 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008043 // allocate JSFunctions since it does not properly initialize
8044 // the shared part of the function. Since the receiver is
8045 // ignored anyway, we use the global object as the receiver
8046 // instead of a new JSFunction object. This way, errors are
8047 // reported the same way whether or not 'Function' is called
8048 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008049 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008051 }
8052
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008053 // The function should be compiled for the optimization hints to be
8054 // available. We cannot use EnsureCompiled because that forces a
8055 // compilation through the shared function info which makes it
8056 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008057 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008058 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008059
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008060 if (!function->has_initial_map() &&
8061 shared->IsInobjectSlackTrackingInProgress()) {
8062 // The tracking is already in progress for another function. We can only
8063 // track one initial_map at a time, so we force the completion before the
8064 // function is called as a constructor for the first time.
8065 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008066 }
8067
8068 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008069 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8070 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008071 // Delay setting the stub if inobject slack tracking is in progress.
8072 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008073 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008074 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 isolate->counters()->constructed_objects()->Increment();
8077 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008078
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008079 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008080}
8081
8082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008084 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008085 ASSERT(args.length() == 1);
8086
8087 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8088 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008089 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008090
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008091 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008092}
8093
8094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008095RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008096 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008097 ASSERT(args.length() == 1);
8098
8099 Handle<JSFunction> function = args.at<JSFunction>(0);
8100#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008101 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008103 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008104 PrintF("]\n");
8105 }
8106#endif
8107
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008108 // Compile the target function. Here we compile using CompileLazyInLoop in
8109 // order to get the optimized version. This helps code like delta-blue
8110 // that calls performance-critical routines through constructors. A
8111 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
8112 // direct call. Since the in-loop tracking takes place through CallICs
8113 // this means that things called through constructors are never known to
8114 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008115 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008116 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117 return Failure::Exception();
8118 }
8119
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008120 // All done. Return the compiled code.
8121 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122 return function->code();
8123}
8124
8125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008126RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008127 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008128 ASSERT(args.length() == 1);
8129 Handle<JSFunction> function = args.at<JSFunction>(0);
8130 // If the function is not optimizable or debugger is active continue using the
8131 // code from the full compiler.
8132 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008133 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008134 if (FLAG_trace_opt) {
8135 PrintF("[failed to optimize ");
8136 function->PrintName();
8137 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8138 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008139 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008140 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008141 function->ReplaceCode(function->shared()->code());
8142 return function->code();
8143 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008144 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008145 return function->code();
8146 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008147 if (FLAG_trace_opt) {
8148 PrintF("[failed to optimize ");
8149 function->PrintName();
8150 PrintF(": optimized compilation failed]\n");
8151 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008152 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008153 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008154}
8155
8156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008157RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008158 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008159 ASSERT(args.length() == 1);
8160 RUNTIME_ASSERT(args[0]->IsSmi());
8161 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008162 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008163 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8164 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008165 int frames = deoptimizer->output_count();
8166
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008167 deoptimizer->MaterializeHeapNumbers();
8168 delete deoptimizer;
8169
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008170 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008171 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008172 for (int i = 0; i < frames - 1; i++) it.Advance();
8173 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008174
8175 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008176 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008177 Handle<Object> arguments;
8178 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008179 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008180 if (arguments.is_null()) {
8181 // FunctionGetArguments can't throw an exception, so cast away the
8182 // doubt with an assert.
8183 arguments = Handle<Object>(
8184 Accessors::FunctionGetArguments(*function,
8185 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008186 ASSERT(*arguments != isolate->heap()->null_value());
8187 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008188 }
8189 frame->SetExpression(i, *arguments);
8190 }
8191 }
8192
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008193 if (type == Deoptimizer::EAGER) {
8194 RUNTIME_ASSERT(function->IsOptimized());
8195 } else {
8196 RUNTIME_ASSERT(!function->IsOptimized());
8197 }
8198
8199 // Avoid doing too much work when running with --always-opt and keep
8200 // the optimized code around.
8201 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008202 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008203 }
8204
8205 // Count the number of optimized activations of the function.
8206 int activations = 0;
8207 while (!it.done()) {
8208 JavaScriptFrame* frame = it.frame();
8209 if (frame->is_optimized() && frame->function() == *function) {
8210 activations++;
8211 }
8212 it.Advance();
8213 }
8214
8215 // TODO(kasperl): For now, we cannot support removing the optimized
8216 // code when we have recursive invocations of the same function.
8217 if (activations == 0) {
8218 if (FLAG_trace_deopt) {
8219 PrintF("[removing optimized code for: ");
8220 function->PrintName();
8221 PrintF("]\n");
8222 }
8223 function->ReplaceCode(function->shared()->code());
8224 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008225 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008226}
8227
8228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008229RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008230 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008231 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008232 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008233}
8234
8235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008236RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008238 ASSERT(args.length() == 1);
8239 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008241
8242 Deoptimizer::DeoptimizeFunction(*function);
8243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008245}
8246
8247
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008248RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8249#if defined(USE_SIMULATOR)
8250 return isolate->heap()->true_value();
8251#else
8252 return isolate->heap()->false_value();
8253#endif
8254}
8255
8256
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008257RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8258 HandleScope scope(isolate);
8259 ASSERT(args.length() == 1);
8260 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8261 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8262 function->MarkForLazyRecompilation();
8263 return isolate->heap()->undefined_value();
8264}
8265
8266
lrn@chromium.org1c092762011-05-09 09:42:16 +00008267RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8268 HandleScope scope(isolate);
8269 ASSERT(args.length() == 1);
8270 if (!V8::UseCrankshaft()) {
8271 return Smi::FromInt(4); // 4 == "never".
8272 }
8273 if (FLAG_always_opt) {
8274 return Smi::FromInt(3); // 3 == "always".
8275 }
8276 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8277 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8278 : Smi::FromInt(2); // 2 == "no".
8279}
8280
8281
8282RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8283 HandleScope scope(isolate);
8284 ASSERT(args.length() == 1);
8285 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8286 return Smi::FromInt(function->shared()->opt_count());
8287}
8288
8289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008290RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008291 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008292 ASSERT(args.length() == 1);
8293 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8294
8295 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008296 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008297
8298 // We have hit a back edge in an unoptimized frame for a function that was
8299 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008300 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008301 // Keep track of whether we've succeeded in optimizing.
8302 bool succeeded = unoptimized->optimizable();
8303 if (succeeded) {
8304 // If we are trying to do OSR when there are already optimized
8305 // activations of the function, it means (a) the function is directly or
8306 // indirectly recursive and (b) an optimized invocation has been
8307 // deoptimized so that we are currently in an unoptimized activation.
8308 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008309 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008310 while (succeeded && !it.done()) {
8311 JavaScriptFrame* frame = it.frame();
8312 succeeded = !frame->is_optimized() || frame->function() != *function;
8313 it.Advance();
8314 }
8315 }
8316
8317 int ast_id = AstNode::kNoNumber;
8318 if (succeeded) {
8319 // The top JS function is this one, the PC is somewhere in the
8320 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008321 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008322 JavaScriptFrame* frame = it.frame();
8323 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008324 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008325 ASSERT(unoptimized->contains(frame->pc()));
8326
8327 // Use linear search of the unoptimized code's stack check table to find
8328 // the AST id matching the PC.
8329 Address start = unoptimized->instruction_start();
8330 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008331 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008332 uint32_t table_length = Memory::uint32_at(table_cursor);
8333 table_cursor += kIntSize;
8334 for (unsigned i = 0; i < table_length; ++i) {
8335 // Table entries are (AST id, pc offset) pairs.
8336 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8337 if (pc_offset == target_pc_offset) {
8338 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8339 break;
8340 }
8341 table_cursor += 2 * kIntSize;
8342 }
8343 ASSERT(ast_id != AstNode::kNoNumber);
8344 if (FLAG_trace_osr) {
8345 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8346 function->PrintName();
8347 PrintF("]\n");
8348 }
8349
8350 // Try to compile the optimized code. A true return value from
8351 // CompileOptimized means that compilation succeeded, not necessarily
8352 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008353 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8354 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008355 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8356 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008357 if (data->OsrPcOffset()->value() >= 0) {
8358 if (FLAG_trace_osr) {
8359 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008360 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008361 }
8362 ASSERT(data->OsrAstId()->value() == ast_id);
8363 } else {
8364 // We may never generate the desired OSR entry if we emit an
8365 // early deoptimize.
8366 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008367 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008368 } else {
8369 succeeded = false;
8370 }
8371 }
8372
8373 // Revert to the original stack checks in the original unoptimized code.
8374 if (FLAG_trace_osr) {
8375 PrintF("[restoring original stack checks in ");
8376 function->PrintName();
8377 PrintF("]\n");
8378 }
8379 StackCheckStub check_stub;
8380 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008381 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008382 Deoptimizer::RevertStackCheckCode(*unoptimized,
8383 *check_code,
8384 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008385
8386 // Allow OSR only at nesting level zero again.
8387 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8388
8389 // If the optimization attempt succeeded, return the AST id tagged as a
8390 // smi. This tells the builtin that we need to translate the unoptimized
8391 // frame to an optimized one.
8392 if (succeeded) {
8393 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8394 return Smi::FromInt(ast_id);
8395 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008396 if (function->IsMarkedForLazyRecompilation()) {
8397 function->ReplaceCode(function->shared()->code());
8398 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008399 return Smi::FromInt(-1);
8400 }
8401}
8402
8403
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008404RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8405 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8406 return isolate->heap()->undefined_value();
8407}
8408
8409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008410RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008411 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008412 ASSERT(args.length() == 1);
8413 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8414 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8415}
8416
8417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008418RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008420 ASSERT(args.length() == 1);
8421 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8422 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8423}
8424
8425
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008426RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008428 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008429
kasper.lund7276f142008-07-30 08:49:36 +00008430 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008431 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008432 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008433 { MaybeObject* maybe_result =
8434 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008435 if (!maybe_result->ToObject(&result)) return maybe_result;
8436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008437
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008438 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008439
kasper.lund7276f142008-07-30 08:49:36 +00008440 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008441}
8442
lrn@chromium.org303ada72010-10-27 09:33:13 +00008443
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008444RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8445 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008446 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008447 JSObject* extension_object;
8448 if (args[0]->IsJSObject()) {
8449 extension_object = JSObject::cast(args[0]);
8450 } else {
8451 // Convert the object to a proper JavaScript object.
8452 MaybeObject* maybe_js_object = args[0]->ToObject();
8453 if (!maybe_js_object->To(&extension_object)) {
8454 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8455 HandleScope scope(isolate);
8456 Handle<Object> handle = args.at<Object>(0);
8457 Handle<Object> result =
8458 isolate->factory()->NewTypeError("with_expression",
8459 HandleVector(&handle, 1));
8460 return isolate->Throw(*result);
8461 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008462 return maybe_js_object;
8463 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008464 }
8465 }
8466
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008467 JSFunction* function;
8468 if (args[1]->IsSmi()) {
8469 // A smi sentinel indicates a context nested inside global code rather
8470 // than some function. There is a canonical empty function that can be
8471 // gotten from the global context.
8472 function = isolate->context()->global_context()->closure();
8473 } else {
8474 function = JSFunction::cast(args[1]);
8475 }
8476
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008477 Context* context;
8478 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008479 isolate->heap()->AllocateWithContext(function,
8480 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008481 extension_object);
8482 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008484 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008485}
8486
8487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008489 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008490 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008491 String* name = String::cast(args[0]);
8492 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008493 JSFunction* function;
8494 if (args[2]->IsSmi()) {
8495 // A smi sentinel indicates a context nested inside global code rather
8496 // than some function. There is a canonical empty function that can be
8497 // gotten from the global context.
8498 function = isolate->context()->global_context()->closure();
8499 } else {
8500 function = JSFunction::cast(args[2]);
8501 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008502 Context* context;
8503 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008504 isolate->heap()->AllocateCatchContext(function,
8505 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008506 name,
8507 thrown_object);
8508 if (!maybe_context->To(&context)) return maybe_context;
8509 isolate->set_context(context);
8510 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008511}
8512
8513
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008514RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8515 NoHandleAllocation ha;
8516 ASSERT(args.length() == 2);
8517 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8518 JSFunction* function;
8519 if (args[1]->IsSmi()) {
8520 // A smi sentinel indicates a context nested inside global code rather
8521 // than some function. There is a canonical empty function that can be
8522 // gotten from the global context.
8523 function = isolate->context()->global_context()->closure();
8524 } else {
8525 function = JSFunction::cast(args[1]);
8526 }
8527 Context* context;
8528 MaybeObject* maybe_context =
8529 isolate->heap()->AllocateBlockContext(function,
8530 isolate->context(),
8531 scope_info);
8532 if (!maybe_context->To(&context)) return maybe_context;
8533 isolate->set_context(context);
8534 return context;
8535}
8536
8537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008538RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008539 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008540 ASSERT(args.length() == 2);
8541
8542 CONVERT_ARG_CHECKED(Context, context, 0);
8543 CONVERT_ARG_CHECKED(String, name, 1);
8544
8545 int index;
8546 PropertyAttributes attributes;
8547 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008548 BindingFlags binding_flags;
8549 Handle<Object> holder = context->Lookup(name,
8550 flags,
8551 &index,
8552 &attributes,
8553 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008554
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008555 // If the slot was not found the result is true.
8556 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008557 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008558 }
8559
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008560 // If the slot was found in a context, it should be DONT_DELETE.
8561 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008562 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008563 }
8564
8565 // The slot was found in a JSObject, either a context extension object,
8566 // the global object, or an arguments object. Try to delete it
8567 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8568 // which allows deleting all parameters in functions that mention
8569 // 'arguments', we do this even for the case of slots found on an
8570 // arguments object. The slot was found on an arguments object if the
8571 // index is non-negative.
8572 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8573 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008574 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008575 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008576 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008578}
8579
8580
ager@chromium.orga1645e22009-09-09 19:27:10 +00008581// A mechanism to return a pair of Object pointers in registers (if possible).
8582// How this is achieved is calling convention-dependent.
8583// All currently supported x86 compiles uses calling conventions that are cdecl
8584// variants where a 64-bit value is returned in two 32-bit registers
8585// (edx:eax on ia32, r1:r0 on ARM).
8586// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8587// In Win64 calling convention, a struct of two pointers is returned in memory,
8588// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008589#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008590struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008591 MaybeObject* x;
8592 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008593};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008594
lrn@chromium.org303ada72010-10-27 09:33:13 +00008595static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008596 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008597 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8598 // In Win64 they are assigned to a hidden first argument.
8599 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008600}
8601#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008602typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008603static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008604 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008605 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008606}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008607#endif
8608
8609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008610static inline MaybeObject* Unhole(Heap* heap,
8611 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008612 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8614 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008615 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008616}
8617
8618
danno@chromium.org40cb8782011-05-25 07:58:50 +00008619static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8620 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008621 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008622 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008623 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008624 JSFunction* context_extension_function =
8625 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008626 // If the holder isn't a context extension object, we just return it
8627 // as the receiver. This allows arguments objects to be used as
8628 // receivers, but only if they are put in the context scope chain
8629 // explicitly via a with-statement.
8630 Object* constructor = holder->map()->constructor();
8631 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008632 // Fall back to using the global object as the implicit receiver if
8633 // the property turns out to be a local variable allocated in a
8634 // context extension object - introduced via eval. Implicit global
8635 // receivers are indicated with the hole value.
8636 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008637}
8638
8639
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008640static ObjectPair LoadContextSlotHelper(Arguments args,
8641 Isolate* isolate,
8642 bool throw_error) {
8643 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008644 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008645
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008646 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008647 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008648 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008649 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008650 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651
8652 int index;
8653 PropertyAttributes attributes;
8654 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008655 BindingFlags binding_flags;
8656 Handle<Object> holder = context->Lookup(name,
8657 flags,
8658 &index,
8659 &attributes,
8660 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008662 // If the index is non-negative, the slot has been found in a local
8663 // variable or a parameter. Read it from the context object or the
8664 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008666 // If the "property" we were looking for is a local variable or an
8667 // argument in a context, the receiver is the global object; see
8668 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008669 //
8670 // Use the hole as the receiver to signal that the receiver is
8671 // implicit and that the global receiver should be used.
8672 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008673 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008674 ? Context::cast(*holder)->get(index)
8675 : JSObject::cast(*holder)->GetElement(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008676 // Check for uninitialized bindings.
8677 if (holder->IsContext() &&
8678 binding_flags == MUTABLE_CHECK_INITIALIZED &&
8679 value->IsTheHole()) {
8680 Handle<Object> reference_error =
8681 isolate->factory()->NewReferenceError("not_defined",
8682 HandleVector(&name, 1));
8683 return MakePair(isolate->Throw(*reference_error), NULL);
8684 } else {
8685 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8686 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 }
8688
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008689 // If the holder is found, we read the property from it.
8690 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008691 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008692 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008693 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008694 if (object->IsGlobalObject()) {
8695 receiver = GlobalObject::cast(object)->global_receiver();
8696 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008697 // Use the hole as the receiver to signal that the receiver is
8698 // implicit and that the global receiver should be used.
8699 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008700 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008701 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008702 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008703
8704 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008705 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008706
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008707 // No need to unhole the value here. This is taken care of by the
8708 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008709 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008710 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008711 }
8712
8713 if (throw_error) {
8714 // The property doesn't exist - throw exception.
8715 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008716 isolate->factory()->NewReferenceError("not_defined",
8717 HandleVector(&name, 1));
8718 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008720 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008721 return MakePair(isolate->heap()->undefined_value(),
8722 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008723 }
8724}
8725
8726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008727RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008728 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729}
8730
8731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008732RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008733 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008734}
8735
8736
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008737RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008738 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008739 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008741 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008742 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008743 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008744 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008745 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8746 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008747 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748
8749 int index;
8750 PropertyAttributes attributes;
8751 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008752 BindingFlags binding_flags;
8753 Handle<Object> holder = context->Lookup(name,
8754 flags,
8755 &index,
8756 &attributes,
8757 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008758
8759 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008760 if (holder->IsContext()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008761 Handle<Context> context = Handle<Context>::cast(holder);
8762 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8763 context->get(index)->IsTheHole()) {
8764 Handle<Object> error =
8765 isolate->factory()->NewReferenceError("not_defined",
8766 HandleVector(&name, 1));
8767 return isolate->Throw(*error);
8768 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769 // Ignore if read_only variable.
8770 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008771 // Context is a fixed array and set cannot fail.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008772 context->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008773 } else if (strict_mode == kStrictMode) {
8774 // Setting read only property in strict mode.
8775 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008776 isolate->factory()->NewTypeError("strict_cannot_assign",
8777 HandleVector(&name, 1));
8778 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779 }
8780 } else {
8781 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008782 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008783 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008784 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008785 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008786 return Failure::Exception();
8787 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008788 }
8789 return *value;
8790 }
8791
8792 // Slow case: The property is not in a FixedArray context.
8793 // It is either in an JSObject extension context or it was not found.
8794 Handle<JSObject> context_ext;
8795
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008796 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008798 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008799 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008800 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008801 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008802
8803 if (strict_mode == kStrictMode) {
8804 // Throw in strict mode (assignment to undefined variable).
8805 Handle<Object> error =
8806 isolate->factory()->NewReferenceError(
8807 "not_defined", HandleVector(&name, 1));
8808 return isolate->Throw(*error);
8809 }
8810 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008811 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008812 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008813 }
8814
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008815 // Set the property, but ignore if read_only variable on the context
8816 // extension object itself.
8817 if ((attributes & READ_ONLY) == 0 ||
8818 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008819 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008820 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008821 SetProperty(context_ext, name, value, NONE, strict_mode));
8822 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008823 // Setting read only property in strict mode.
8824 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008825 isolate->factory()->NewTypeError(
8826 "strict_cannot_assign", HandleVector(&name, 1));
8827 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828 }
8829 return *value;
8830}
8831
8832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008833RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008834 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008835 ASSERT(args.length() == 1);
8836
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008837 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008838}
8839
8840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008841RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008842 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843 ASSERT(args.length() == 1);
8844
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008845 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008846}
8847
8848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008849RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008850 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008851 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008852}
8853
8854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008855RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008856 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857 ASSERT(args.length() == 1);
8858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008859 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008860 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008861 isolate->factory()->NewReferenceError("not_defined",
8862 HandleVector(&name, 1));
8863 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864}
8865
8866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008867RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008868 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008869
8870 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008871 if (isolate->stack_guard()->IsStackOverflow()) {
8872 NoHandleAllocation na;
8873 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008874 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008875
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008876 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877}
8878
8879
8880// NOTE: These PrintXXX functions are defined for all builds (not just
8881// DEBUG builds) because we may want to be able to trace function
8882// calls in all modes.
8883static void PrintString(String* str) {
8884 // not uncommon to have empty strings
8885 if (str->length() > 0) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008886 SmartArrayPointer<char> s =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8888 PrintF("%s", *s);
8889 }
8890}
8891
8892
8893static void PrintObject(Object* obj) {
8894 if (obj->IsSmi()) {
8895 PrintF("%d", Smi::cast(obj)->value());
8896 } else if (obj->IsString() || obj->IsSymbol()) {
8897 PrintString(String::cast(obj));
8898 } else if (obj->IsNumber()) {
8899 PrintF("%g", obj->Number());
8900 } else if (obj->IsFailure()) {
8901 PrintF("<failure>");
8902 } else if (obj->IsUndefined()) {
8903 PrintF("<undefined>");
8904 } else if (obj->IsNull()) {
8905 PrintF("<null>");
8906 } else if (obj->IsTrue()) {
8907 PrintF("<true>");
8908 } else if (obj->IsFalse()) {
8909 PrintF("<false>");
8910 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008911 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912 }
8913}
8914
8915
8916static int StackSize() {
8917 int n = 0;
8918 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8919 return n;
8920}
8921
8922
8923static void PrintTransition(Object* result) {
8924 // indentation
8925 { const int nmax = 80;
8926 int n = StackSize();
8927 if (n <= nmax)
8928 PrintF("%4d:%*s", n, n, "");
8929 else
8930 PrintF("%4d:%*s", n, nmax, "...");
8931 }
8932
8933 if (result == NULL) {
8934 // constructor calls
8935 JavaScriptFrameIterator it;
8936 JavaScriptFrame* frame = it.frame();
8937 if (frame->IsConstructor()) PrintF("new ");
8938 // function name
8939 Object* fun = frame->function();
8940 if (fun->IsJSFunction()) {
8941 PrintObject(JSFunction::cast(fun)->shared()->name());
8942 } else {
8943 PrintObject(fun);
8944 }
8945 // function arguments
8946 // (we are intentionally only printing the actually
8947 // supplied parameters, not all parameters required)
8948 PrintF("(this=");
8949 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008950 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951 for (int i = 0; i < length; i++) {
8952 PrintF(", ");
8953 PrintObject(frame->GetParameter(i));
8954 }
8955 PrintF(") {\n");
8956
8957 } else {
8958 // function result
8959 PrintF("} -> ");
8960 PrintObject(result);
8961 PrintF("\n");
8962 }
8963}
8964
8965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008966RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008967 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008968 NoHandleAllocation ha;
8969 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008970 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971}
8972
8973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008974RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975 NoHandleAllocation ha;
8976 PrintTransition(args[0]);
8977 return args[0]; // return TOS
8978}
8979
8980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008981RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 NoHandleAllocation ha;
8983 ASSERT(args.length() == 1);
8984
8985#ifdef DEBUG
8986 if (args[0]->IsString()) {
8987 // If we have a string, assume it's a code "marker"
8988 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008989 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008991 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8992 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008993 } else {
8994 PrintF("DebugPrint: ");
8995 }
8996 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008997 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008998 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008999 HeapObject::cast(args[0])->map()->Print();
9000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009002 // ShortPrint is available in release mode. Print is not.
9003 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004#endif
9005 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009006 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007
9008 return args[0]; // return TOS
9009}
9010
9011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009012RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009013 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 isolate->PrintStack();
9016 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017}
9018
9019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009020RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009022 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023
9024 // According to ECMA-262, section 15.9.1, page 117, the precision of
9025 // the number in a Date object representing a particular instant in
9026 // time is milliseconds. Therefore, we floor the result of getting
9027 // the OS time.
9028 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009029 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030}
9031
9032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009033RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009034 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009035 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009036
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009037 CONVERT_ARG_CHECKED(String, str, 0);
9038 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009040 CONVERT_ARG_CHECKED(JSArray, output, 1);
9041 RUNTIME_ASSERT(output->HasFastElements());
9042
9043 AssertNoAllocation no_allocation;
9044
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009045 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009046 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9047 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009048 String::FlatContent str_content = str->GetFlatContent();
9049 if (str_content.IsAscii()) {
9050 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009051 output_array,
9052 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009054 ASSERT(str_content.IsTwoByte());
9055 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009056 output_array,
9057 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009058 }
9059
9060 if (result) {
9061 return *output;
9062 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064 }
9065}
9066
9067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009068RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069 NoHandleAllocation ha;
9070 ASSERT(args.length() == 1);
9071
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009072 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009073 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009074 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075}
9076
9077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009078RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009080 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009082 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083}
9084
9085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009086RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009087 NoHandleAllocation ha;
9088 ASSERT(args.length() == 1);
9089
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009090 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009091 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092}
9093
9094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009095RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009096 ASSERT(args.length() == 1);
9097 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009098 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009099 return JSGlobalObject::cast(global)->global_receiver();
9100}
9101
9102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009103RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009105 ASSERT_EQ(1, args.length());
9106 CONVERT_ARG_CHECKED(String, source, 0);
9107
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009108 source = Handle<String>(source->TryFlattenGetString());
9109 // Optimized fast case where we only have ascii characters.
9110 Handle<Object> result;
9111 if (source->IsSeqAsciiString()) {
9112 result = JsonParser<true>::Parse(source);
9113 } else {
9114 result = JsonParser<false>::Parse(source);
9115 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009116 if (result.is_null()) {
9117 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009118 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009119 return Failure::Exception();
9120 }
9121 return *result;
9122}
9123
9124
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009125bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9126 Handle<Context> context) {
9127 if (context->allow_code_gen_from_strings()->IsFalse()) {
9128 // Check with callback if set.
9129 AllowCodeGenerationFromStringsCallback callback =
9130 isolate->allow_code_gen_callback();
9131 if (callback == NULL) {
9132 // No callback set and code generation disallowed.
9133 return false;
9134 } else {
9135 // Callback set. Let it decide if code generation is allowed.
9136 VMState state(isolate, EXTERNAL);
9137 return callback(v8::Utils::ToLocal(context));
9138 }
9139 }
9140 return true;
9141}
9142
9143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009144RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009145 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009146 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009147 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009148
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009149 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009150 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009151
9152 // Check if global context allows code generation from
9153 // strings. Throw an exception if it doesn't.
9154 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9155 return isolate->Throw(*isolate->factory()->NewError(
9156 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9157 }
9158
9159 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009160 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9161 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009162 true,
9163 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009164 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009166 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9167 context,
9168 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009169 return *fun;
9170}
9171
9172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009173static ObjectPair CompileGlobalEval(Isolate* isolate,
9174 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009175 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009176 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009177 Handle<Context> context = Handle<Context>(isolate->context());
9178 Handle<Context> global_context = Handle<Context>(context->global_context());
9179
9180 // Check if global context allows code generation from
9181 // strings. Throw an exception if it doesn't.
9182 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9183 isolate->Throw(*isolate->factory()->NewError(
9184 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9185 return MakePair(Failure::Exception(), NULL);
9186 }
9187
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009188 // Deal with a normal eval call with a string argument. Compile it
9189 // and return the compiled function bound in the local context.
9190 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9191 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009192 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009193 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009194 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009195 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 Handle<JSFunction> compiled =
9197 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009198 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009199 return MakePair(*compiled, *receiver);
9200}
9201
9202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009203RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009204 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009207 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009208 Handle<Object> receiver; // Will be overwritten.
9209
9210 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009211 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009212#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009214 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009215 StackFrameLocator locator;
9216 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009217 ASSERT(Context::cast(frame->context()) == *context);
9218#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009219
9220 // Find where the 'eval' symbol is bound. It is unaliased only if
9221 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009222 int index = -1;
9223 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009224 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009225 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9227 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009228 &index,
9229 &attributes,
9230 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009231 // Stop search when eval is found or when the global context is
9232 // reached.
9233 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009234 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009235 }
9236
iposva@chromium.org245aa852009-02-10 00:49:54 +00009237 // If eval could not be resolved, it has been deleted and we need to
9238 // throw a reference error.
9239 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009241 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009242 isolate->factory()->NewReferenceError("not_defined",
9243 HandleVector(&name, 1));
9244 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009245 }
9246
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009247 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009248 // 'eval' is not bound in the global context. Just call the function
9249 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009250 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009251 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009252 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009253 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009254 }
9255
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009256 // 'eval' is bound in the global context, but it may have been overwritten.
9257 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009259 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009260 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009261 }
9262
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009263 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009264 return CompileGlobalEval(isolate,
9265 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009266 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009267 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009268}
9269
9270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009271RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009272 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009273
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009274 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009275 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009276
9277 // 'eval' is bound in the global context, but it may have been overwritten.
9278 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009280 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009281 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009282 }
9283
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009284 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009285 return CompileGlobalEval(isolate,
9286 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009287 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009288 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009289}
9290
9291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009292RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293 // This utility adjusts the property attributes for newly created Function
9294 // object ("new Function(...)") by changing the map.
9295 // All it does is changing the prototype property to enumerable
9296 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 ASSERT(args.length() == 1);
9299 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009300
9301 Handle<Map> map = func->shared()->strict_mode()
9302 ? isolate->strict_mode_function_instance_map()
9303 : isolate->function_instance_map();
9304
9305 ASSERT(func->map()->instance_type() == map->instance_type());
9306 ASSERT(func->map()->instance_size() == map->instance_size());
9307 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009308 return *func;
9309}
9310
9311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009312RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009313 // Allocate a block of memory in NewSpace (filled with a filler).
9314 // Use as fallback for allocation in generated code when NewSpace
9315 // is full.
9316 ASSERT(args.length() == 1);
9317 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9318 int size = size_smi->value();
9319 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9320 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009321 Heap* heap = isolate->heap();
9322 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009323 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009324 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009326 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009327 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009328 }
9329 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009330 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009331}
9332
9333
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009334// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009335// array. Returns true if the element was pushed on the stack and
9336// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009337RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009338 ASSERT(args.length() == 2);
9339 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009340 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009341 RUNTIME_ASSERT(array->HasFastElements());
9342 int length = Smi::cast(array->length())->value();
9343 FixedArray* elements = FixedArray::cast(array->elements());
9344 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009346 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009347 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009348 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009349 { MaybeObject* maybe_obj =
9350 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009351 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9352 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009354}
9355
9356
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009357/**
9358 * A simple visitor visits every element of Array's.
9359 * The backend storage can be a fixed array for fast elements case,
9360 * or a dictionary for sparse array. Since Dictionary is a subtype
9361 * of FixedArray, the class can be used by both fast and slow cases.
9362 * The second parameter of the constructor, fast_elements, specifies
9363 * whether the storage is a FixedArray or Dictionary.
9364 *
9365 * An index limit is used to deal with the situation that a result array
9366 * length overflows 32-bit non-negative integer.
9367 */
9368class ArrayConcatVisitor {
9369 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009370 ArrayConcatVisitor(Isolate* isolate,
9371 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009372 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009373 isolate_(isolate),
9374 storage_(Handle<FixedArray>::cast(
9375 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009376 index_offset_(0u),
9377 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009378
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009379 ~ArrayConcatVisitor() {
9380 clear_storage();
9381 }
9382
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009383 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009384 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009385 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009386
9387 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009388 if (index < static_cast<uint32_t>(storage_->length())) {
9389 storage_->set(index, *elm);
9390 return;
9391 }
9392 // Our initial estimate of length was foiled, possibly by
9393 // getters on the arrays increasing the length of later arrays
9394 // during iteration.
9395 // This shouldn't happen in anything but pathological cases.
9396 SetDictionaryMode(index);
9397 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009398 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009399 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009400 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009401 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009402 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009403 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009404 // Dictionary needed to grow.
9405 clear_storage();
9406 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009407 }
9408}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009409
9410 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009411 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9412 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009413 } else {
9414 index_offset_ += delta;
9415 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009416 }
9417
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009418 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009419 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009420 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009421 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009422 Handle<Map> map;
9423 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009424 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009425 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009427 }
9428 array->set_map(*map);
9429 array->set_length(*length);
9430 array->set_elements(*storage_);
9431 return array;
9432 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009433
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009434 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009435 // Convert storage to dictionary mode.
9436 void SetDictionaryMode(uint32_t index) {
9437 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009438 Handle<FixedArray> current_storage(*storage_);
9439 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009440 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009441 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9442 for (uint32_t i = 0; i < current_length; i++) {
9443 HandleScope loop_scope;
9444 Handle<Object> element(current_storage->get(i));
9445 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009446 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009447 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009448 if (!new_storage.is_identical_to(slow_storage)) {
9449 slow_storage = loop_scope.CloseAndEscape(new_storage);
9450 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009451 }
9452 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009453 clear_storage();
9454 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009455 fast_elements_ = false;
9456 }
9457
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009458 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009459 isolate_->global_handles()->Destroy(
9460 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009461 }
9462
9463 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009464 storage_ = Handle<FixedArray>::cast(
9465 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009466 }
9467
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009469 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009470 // Index after last seen index. Always less than or equal to
9471 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009472 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009473 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009474};
9475
9476
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009477static uint32_t EstimateElementCount(Handle<JSArray> array) {
9478 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9479 int element_count = 0;
9480 switch (array->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009481 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009482 // Fast elements can't have lengths that are not representable by
9483 // a 32-bit signed integer.
9484 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9485 int fast_length = static_cast<int>(length);
9486 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9487 for (int i = 0; i < fast_length; i++) {
9488 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009489 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009490 break;
9491 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009492 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009493 Handle<NumberDictionary> dictionary(
9494 NumberDictionary::cast(array->elements()));
9495 int capacity = dictionary->Capacity();
9496 for (int i = 0; i < capacity; i++) {
9497 Handle<Object> key(dictionary->KeyAt(i));
9498 if (dictionary->IsKey(*key)) {
9499 element_count++;
9500 }
9501 }
9502 break;
9503 }
9504 default:
9505 // External arrays are always dense.
9506 return length;
9507 }
9508 // As an estimate, we assume that the prototype doesn't contain any
9509 // inherited elements.
9510 return element_count;
9511}
9512
9513
9514
9515template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009516static void IterateExternalArrayElements(Isolate* isolate,
9517 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009518 bool elements_are_ints,
9519 bool elements_are_guaranteed_smis,
9520 ArrayConcatVisitor* visitor) {
9521 Handle<ExternalArrayClass> array(
9522 ExternalArrayClass::cast(receiver->elements()));
9523 uint32_t len = static_cast<uint32_t>(array->length());
9524
9525 ASSERT(visitor != NULL);
9526 if (elements_are_ints) {
9527 if (elements_are_guaranteed_smis) {
9528 for (uint32_t j = 0; j < len; j++) {
9529 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009530 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009531 visitor->visit(j, e);
9532 }
9533 } else {
9534 for (uint32_t j = 0; j < len; j++) {
9535 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009536 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009537 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9538 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9539 visitor->visit(j, e);
9540 } else {
9541 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009543 visitor->visit(j, e);
9544 }
9545 }
9546 }
9547 } else {
9548 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009550 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009551 visitor->visit(j, e);
9552 }
9553 }
9554}
9555
9556
9557// Used for sorting indices in a List<uint32_t>.
9558static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9559 uint32_t a = *ap;
9560 uint32_t b = *bp;
9561 return (a == b) ? 0 : (a < b) ? -1 : 1;
9562}
9563
9564
9565static void CollectElementIndices(Handle<JSObject> object,
9566 uint32_t range,
9567 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009568 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009569 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009570 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009571 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9572 uint32_t length = static_cast<uint32_t>(elements->length());
9573 if (range < length) length = range;
9574 for (uint32_t i = 0; i < length; i++) {
9575 if (!elements->get(i)->IsTheHole()) {
9576 indices->Add(i);
9577 }
9578 }
9579 break;
9580 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009581 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009582 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009583 uint32_t capacity = dict->Capacity();
9584 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009585 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009586 Handle<Object> k(dict->KeyAt(j));
9587 if (dict->IsKey(*k)) {
9588 ASSERT(k->IsNumber());
9589 uint32_t index = static_cast<uint32_t>(k->Number());
9590 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009591 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009592 }
9593 }
9594 }
9595 break;
9596 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009597 default: {
9598 int dense_elements_length;
9599 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009600 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009601 dense_elements_length =
9602 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009603 break;
9604 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009605 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009606 dense_elements_length =
9607 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009608 break;
9609 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009610 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009611 dense_elements_length =
9612 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009613 break;
9614 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009615 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009616 dense_elements_length =
9617 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009618 break;
9619 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009620 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009621 dense_elements_length =
9622 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009623 break;
9624 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009625 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009626 dense_elements_length =
9627 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009628 break;
9629 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009630 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009631 dense_elements_length =
9632 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 break;
9634 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009635 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009636 dense_elements_length =
9637 ExternalFloatArray::cast(object->elements())->length();
9638 break;
9639 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009640 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009641 dense_elements_length =
9642 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 break;
9644 }
9645 default:
9646 UNREACHABLE();
9647 dense_elements_length = 0;
9648 break;
9649 }
9650 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9651 if (range <= length) {
9652 length = range;
9653 // We will add all indices, so we might as well clear it first
9654 // and avoid duplicates.
9655 indices->Clear();
9656 }
9657 for (uint32_t i = 0; i < length; i++) {
9658 indices->Add(i);
9659 }
9660 if (length == range) return; // All indices accounted for already.
9661 break;
9662 }
9663 }
9664
9665 Handle<Object> prototype(object->GetPrototype());
9666 if (prototype->IsJSObject()) {
9667 // The prototype will usually have no inherited element indices,
9668 // but we have to check.
9669 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9670 }
9671}
9672
9673
9674/**
9675 * A helper function that visits elements of a JSArray in numerical
9676 * order.
9677 *
9678 * The visitor argument called for each existing element in the array
9679 * with the element index and the element's value.
9680 * Afterwards it increments the base-index of the visitor by the array
9681 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009682 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009683 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684static bool IterateElements(Isolate* isolate,
9685 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009686 ArrayConcatVisitor* visitor) {
9687 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9688 switch (receiver->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009689 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009690 // Run through the elements FixedArray and use HasElement and GetElement
9691 // to check the prototype for missing elements.
9692 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9693 int fast_length = static_cast<int>(length);
9694 ASSERT(fast_length <= elements->length());
9695 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009696 HandleScope loop_scope(isolate);
9697 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009698 if (!element_value->IsTheHole()) {
9699 visitor->visit(j, element_value);
9700 } else if (receiver->HasElement(j)) {
9701 // Call GetElement on receiver, not its prototype, or getters won't
9702 // have the correct receiver.
9703 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009704 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009705 visitor->visit(j, element_value);
9706 }
9707 }
9708 break;
9709 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009710 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009711 Handle<NumberDictionary> dict(receiver->element_dictionary());
9712 List<uint32_t> indices(dict->Capacity() / 2);
9713 // Collect all indices in the object and the prototypes less
9714 // than length. This might introduce duplicates in the indices list.
9715 CollectElementIndices(receiver, length, &indices);
9716 indices.Sort(&compareUInt32);
9717 int j = 0;
9718 int n = indices.length();
9719 while (j < n) {
9720 HandleScope loop_scope;
9721 uint32_t index = indices[j];
9722 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009723 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009724 visitor->visit(index, element);
9725 // Skip to next different index (i.e., omit duplicates).
9726 do {
9727 j++;
9728 } while (j < n && indices[j] == index);
9729 }
9730 break;
9731 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009732 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009733 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9734 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009736 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009737 visitor->visit(j, e);
9738 }
9739 break;
9740 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009741 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009742 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009743 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009744 break;
9745 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009746 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009747 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009748 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009749 break;
9750 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009751 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009752 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754 break;
9755 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009756 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009757 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009758 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009759 break;
9760 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009761 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009764 break;
9765 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009766 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009768 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009769 break;
9770 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009771 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009772 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009774 break;
9775 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009776 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009777 IterateExternalArrayElements<ExternalDoubleArray, double>(
9778 isolate, receiver, false, false, visitor);
9779 break;
9780 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009781 default:
9782 UNREACHABLE();
9783 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009784 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009785 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009786 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009787}
9788
9789
9790/**
9791 * Array::concat implementation.
9792 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009793 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009794 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009795 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009796RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009797 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009798 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009799
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009800 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9801 int argument_count = static_cast<int>(arguments->length()->Number());
9802 RUNTIME_ASSERT(arguments->HasFastElements());
9803 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009804
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009805 // Pass 1: estimate the length and number of elements of the result.
9806 // The actual length can be larger if any of the arguments have getters
9807 // that mutate other arguments (but will otherwise be precise).
9808 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009809
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009810 uint32_t estimate_result_length = 0;
9811 uint32_t estimate_nof_elements = 0;
9812 {
9813 for (int i = 0; i < argument_count; i++) {
9814 HandleScope loop_scope;
9815 Handle<Object> obj(elements->get(i));
9816 uint32_t length_estimate;
9817 uint32_t element_estimate;
9818 if (obj->IsJSArray()) {
9819 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9820 length_estimate =
9821 static_cast<uint32_t>(array->length()->Number());
9822 element_estimate =
9823 EstimateElementCount(array);
9824 } else {
9825 length_estimate = 1;
9826 element_estimate = 1;
9827 }
9828 // Avoid overflows by capping at kMaxElementCount.
9829 if (JSObject::kMaxElementCount - estimate_result_length <
9830 length_estimate) {
9831 estimate_result_length = JSObject::kMaxElementCount;
9832 } else {
9833 estimate_result_length += length_estimate;
9834 }
9835 if (JSObject::kMaxElementCount - estimate_nof_elements <
9836 element_estimate) {
9837 estimate_nof_elements = JSObject::kMaxElementCount;
9838 } else {
9839 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009840 }
9841 }
9842 }
9843
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009844 // If estimated number of elements is more than half of length, a
9845 // fixed array (fast case) is more time and space-efficient than a
9846 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009847 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009848
9849 Handle<FixedArray> storage;
9850 if (fast_case) {
9851 // The backing storage array must have non-existing elements to
9852 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009853 storage = isolate->factory()->NewFixedArrayWithHoles(
9854 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009855 } else {
9856 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9857 uint32_t at_least_space_for = estimate_nof_elements +
9858 (estimate_nof_elements >> 2);
9859 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009860 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009861 }
9862
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009863 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009864
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009865 for (int i = 0; i < argument_count; i++) {
9866 Handle<Object> obj(elements->get(i));
9867 if (obj->IsJSArray()) {
9868 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009869 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009870 return Failure::Exception();
9871 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009872 } else {
9873 visitor.visit(0, obj);
9874 visitor.increase_index_offset(1);
9875 }
9876 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009877
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009878 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009879}
9880
9881
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882// This will not allocate (flatten the string), but it may run
9883// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009884RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009885 NoHandleAllocation ha;
9886 ASSERT(args.length() == 1);
9887
9888 CONVERT_CHECKED(String, string, args[0]);
9889 StringInputBuffer buffer(string);
9890 while (buffer.has_more()) {
9891 uint16_t character = buffer.GetNext();
9892 PrintF("%c", character);
9893 }
9894 return string;
9895}
9896
ager@chromium.org5ec48922009-05-05 07:25:34 +00009897// Moves all own elements of an object, that are below a limit, to positions
9898// starting at zero. All undefined values are placed after non-undefined values,
9899// and are followed by non-existing element. Does not change the length
9900// property.
9901// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009902RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009903 ASSERT(args.length() == 2);
9904 CONVERT_CHECKED(JSObject, object, args[0]);
9905 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9906 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009907}
9908
9909
9910// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009911RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912 ASSERT(args.length() == 2);
9913 CONVERT_CHECKED(JSArray, from, args[0]);
9914 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009915 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009916 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009917 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9918 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009919 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009920 } else if (new_elements->map() ==
9921 isolate->heap()->fixed_double_array_map()) {
9922 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009923 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009924 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009925 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009926 Object* new_map;
9927 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009928 to->set_map(Map::cast(new_map));
9929 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009930 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009931 Object* obj;
9932 { MaybeObject* maybe_obj = from->ResetElements();
9933 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9934 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009935 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009936 return to;
9937}
9938
9939
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009940// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009941RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009943 CONVERT_CHECKED(JSObject, object, args[0]);
9944 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009945 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009946 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009947 } else if (object->IsJSArray()) {
9948 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009949 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009950 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009951 }
9952}
9953
9954
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009955RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009956 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009957
9958 ASSERT_EQ(3, args.length());
9959
ager@chromium.orgac091b72010-05-05 07:34:42 +00009960 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009961 Handle<Object> key1 = args.at<Object>(1);
9962 Handle<Object> key2 = args.at<Object>(2);
9963
9964 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009965 if (!key1->ToArrayIndex(&index1)
9966 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009967 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009968 }
9969
ager@chromium.orgac091b72010-05-05 07:34:42 +00009970 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9971 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009972 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009973 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009974 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 RETURN_IF_EMPTY_HANDLE(isolate,
9977 SetElement(jsobject, index1, tmp2, kStrictMode));
9978 RETURN_IF_EMPTY_HANDLE(isolate,
9979 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009980
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009981 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009982}
9983
9984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009986// might have elements. Can either return keys (positive integers) or
9987// intervals (pair of a negative integer (-start-1) followed by a
9988// positive (length)) or undefined values.
9989// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009990RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009992 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009993 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009994 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009995 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009996 // Create an array and get all the keys into it, then remove all the
9997 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009998 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999 int keys_length = keys->length();
10000 for (int i = 0; i < keys_length; i++) {
10001 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010002 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010003 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 // Zap invalid keys.
10005 keys->set_undefined(i);
10006 }
10007 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010010 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010012 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010013 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010014 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010015 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010016 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010017 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010019 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 }
10023}
10024
10025
10026// DefineAccessor takes an optional final argument which is the
10027// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10028// to the way accessors are implemented, it is set for both the getter
10029// and setter on the first call to DefineAccessor and ignored on
10030// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010031RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10033 // Compute attributes.
10034 PropertyAttributes attributes = NONE;
10035 if (args.length() == 5) {
10036 CONVERT_CHECKED(Smi, attrs, args[4]);
10037 int value = attrs->value();
10038 // Only attribute bits should be set.
10039 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10040 attributes = static_cast<PropertyAttributes>(value);
10041 }
10042
10043 CONVERT_CHECKED(JSObject, obj, args[0]);
10044 CONVERT_CHECKED(String, name, args[1]);
10045 CONVERT_CHECKED(Smi, flag, args[2]);
10046 CONVERT_CHECKED(JSFunction, fun, args[3]);
10047 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10048}
10049
10050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010051RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052 ASSERT(args.length() == 3);
10053 CONVERT_CHECKED(JSObject, obj, args[0]);
10054 CONVERT_CHECKED(String, name, args[1]);
10055 CONVERT_CHECKED(Smi, flag, args[2]);
10056 return obj->LookupAccessor(name, flag->value() == 0);
10057}
10058
10059
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010060#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010061RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010062 ASSERT(args.length() == 0);
10063 return Execution::DebugBreakHelper();
10064}
10065
10066
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067// Helper functions for wrapping and unwrapping stack frame ids.
10068static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010069 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010070 return Smi::FromInt(id >> 2);
10071}
10072
10073
10074static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10075 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10076}
10077
10078
10079// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010080// args[0]: debug event listener function to set or null or undefined for
10081// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010082// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010083RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010084 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010085 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10086 args[0]->IsUndefined() ||
10087 args[0]->IsNull());
10088 Handle<Object> callback = args.at<Object>(0);
10089 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010092 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093}
10094
10095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010096RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010097 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010098 isolate->stack_guard()->DebugBreak();
10099 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010100}
10101
10102
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010103static MaybeObject* DebugLookupResultValue(Heap* heap,
10104 Object* receiver,
10105 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010106 LookupResult* result,
10107 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010108 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010109 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010110 case NORMAL:
10111 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010112 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010113 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114 }
10115 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010116 case FIELD:
10117 value =
10118 JSObject::cast(
10119 result->holder())->FastPropertyAt(result->GetFieldIndex());
10120 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010121 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010122 }
10123 return value;
10124 case CONSTANT_FUNCTION:
10125 return result->GetConstantFunction();
10126 case CALLBACKS: {
10127 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010128 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010129 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010130 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010131 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010132 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010133 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010134 maybe_value = heap->isolate()->pending_exception();
10135 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010136 if (caught_exception != NULL) {
10137 *caught_exception = true;
10138 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010139 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010140 }
10141 return value;
10142 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010144 }
10145 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010146 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010147 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010148 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010149 case CONSTANT_TRANSITION:
10150 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010151 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152 default:
10153 UNREACHABLE();
10154 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010155 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010156 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010157}
10158
10159
ager@chromium.org32912102009-01-16 10:38:43 +000010160// Get debugger related details for an object property.
10161// args[0]: object holding property
10162// args[1]: name of the property
10163//
10164// The array returned contains the following information:
10165// 0: Property value
10166// 1: Property details
10167// 2: Property value is exception
10168// 3: Getter function if defined
10169// 4: Setter function if defined
10170// Items 2-4 are only filled if the property has either a getter or a setter
10171// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010172RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010173 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174
10175 ASSERT(args.length() == 2);
10176
10177 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10178 CONVERT_ARG_CHECKED(String, name, 1);
10179
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010180 // Make sure to set the current context to the context before the debugger was
10181 // entered (if the debugger is entered). The reason for switching context here
10182 // is that for some property lookups (accessors and interceptors) callbacks
10183 // into the embedding application can occour, and the embedding application
10184 // could have the assumption that its own global context is the current
10185 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010186 SaveContext save(isolate);
10187 if (isolate->debug()->InDebugger()) {
10188 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010189 }
10190
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010191 // Skip the global proxy as it has no properties and always delegates to the
10192 // real global object.
10193 if (obj->IsJSGlobalProxy()) {
10194 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10195 }
10196
10197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010198 // Check if the name is trivially convertible to an index and get the element
10199 // if so.
10200 uint32_t index;
10201 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010203 Object* element_or_char;
10204 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010205 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010206 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10207 return maybe_element_or_char;
10208 }
10209 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010210 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010212 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010213 }
10214
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010215 // Find the number of objects making up this.
10216 int length = LocalPrototypeChainLength(*obj);
10217
10218 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010219 Handle<JSObject> jsproto = obj;
10220 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010221 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010222 jsproto->LocalLookup(*name, &result);
10223 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010224 // LookupResult is not GC safe as it holds raw object pointers.
10225 // GC can happen later in this code so put the required fields into
10226 // local variables using handles when required for later use.
10227 PropertyType result_type = result.type();
10228 Handle<Object> result_callback_obj;
10229 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10231 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010232 }
10233 Smi* property_details = result.GetPropertyDetails().AsSmi();
10234 // DebugLookupResultValue can cause GC so details from LookupResult needs
10235 // to be copied to handles before this.
10236 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010237 Object* raw_value;
10238 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010239 DebugLookupResultValue(isolate->heap(), *obj, *name,
10240 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010241 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10242 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010243 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010244
10245 // If the callback object is a fixed array then it contains JavaScript
10246 // getter and/or setter.
10247 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10248 result_callback_obj->IsFixedArray();
10249 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010250 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010251 details->set(0, *value);
10252 details->set(1, property_details);
10253 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010254 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010255 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10256 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10257 }
10258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010259 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010260 }
10261 if (i < length - 1) {
10262 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10263 }
10264 }
10265
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267}
10268
10269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010270RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272
10273 ASSERT(args.length() == 2);
10274
10275 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10276 CONVERT_ARG_CHECKED(String, name, 1);
10277
10278 LookupResult result;
10279 obj->Lookup(*name, &result);
10280 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010281 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284}
10285
10286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287// Return the property type calculated from the property details.
10288// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010289RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290 ASSERT(args.length() == 1);
10291 CONVERT_CHECKED(Smi, details, args[0]);
10292 PropertyType type = PropertyDetails(details).type();
10293 return Smi::FromInt(static_cast<int>(type));
10294}
10295
10296
10297// Return the property attribute calculated from the property details.
10298// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010299RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010300 ASSERT(args.length() == 1);
10301 CONVERT_CHECKED(Smi, details, args[0]);
10302 PropertyAttributes attributes = PropertyDetails(details).attributes();
10303 return Smi::FromInt(static_cast<int>(attributes));
10304}
10305
10306
10307// Return the property insertion index calculated from the property details.
10308// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010309RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 ASSERT(args.length() == 1);
10311 CONVERT_CHECKED(Smi, details, args[0]);
10312 int index = PropertyDetails(details).index();
10313 return Smi::FromInt(index);
10314}
10315
10316
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317// Return property value from named interceptor.
10318// args[0]: object
10319// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010320RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 ASSERT(args.length() == 2);
10323 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10324 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10325 CONVERT_ARG_CHECKED(String, name, 1);
10326
10327 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010328 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329}
10330
10331
10332// Return element value from indexed interceptor.
10333// args[0]: object
10334// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010335RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010336 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337 ASSERT(args.length() == 2);
10338 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10339 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10340 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10341
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010342 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343}
10344
10345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010346RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347 ASSERT(args.length() >= 1);
10348 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010349 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 if (isolate->debug()->break_id() == 0 ||
10351 break_id != isolate->debug()->break_id()) {
10352 return isolate->Throw(
10353 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354 }
10355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010356 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357}
10358
10359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010360RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362 ASSERT(args.length() == 1);
10363
10364 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010365 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010366 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10367 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010368 if (!maybe_result->ToObject(&result)) return maybe_result;
10369 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010370
10371 // Count all frames which are relevant to debugging stack trace.
10372 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010373 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010374 if (id == StackFrame::NO_ID) {
10375 // If there is no JavaScript stack frame count is 0.
10376 return Smi::FromInt(0);
10377 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010378
10379 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10380 n += it.frame()->GetInlineCount();
10381 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010382 return Smi::FromInt(n);
10383}
10384
10385
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010386class FrameInspector {
10387 public:
10388 FrameInspector(JavaScriptFrame* frame,
10389 int inlined_frame_index,
10390 Isolate* isolate)
10391 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10392 // Calculate the deoptimized frame.
10393 if (frame->is_optimized()) {
10394 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10395 frame, inlined_frame_index, isolate);
10396 }
10397 has_adapted_arguments_ = frame_->has_adapted_arguments();
10398 is_optimized_ = frame_->is_optimized();
10399 }
10400
10401 ~FrameInspector() {
10402 // Get rid of the calculated deoptimized frame if any.
10403 if (deoptimized_frame_ != NULL) {
10404 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10405 isolate_);
10406 }
10407 }
10408
10409 int GetParametersCount() {
10410 return is_optimized_
10411 ? deoptimized_frame_->parameters_count()
10412 : frame_->ComputeParametersCount();
10413 }
10414 int expression_count() { return deoptimized_frame_->expression_count(); }
10415 Object* GetFunction() {
10416 return is_optimized_
10417 ? deoptimized_frame_->GetFunction()
10418 : frame_->function();
10419 }
10420 Object* GetParameter(int index) {
10421 return is_optimized_
10422 ? deoptimized_frame_->GetParameter(index)
10423 : frame_->GetParameter(index);
10424 }
10425 Object* GetExpression(int index) {
10426 return is_optimized_
10427 ? deoptimized_frame_->GetExpression(index)
10428 : frame_->GetExpression(index);
10429 }
10430
10431 // To inspect all the provided arguments the frame might need to be
10432 // replaced with the arguments frame.
10433 void SetArgumentsFrame(JavaScriptFrame* frame) {
10434 ASSERT(has_adapted_arguments_);
10435 frame_ = frame;
10436 is_optimized_ = frame_->is_optimized();
10437 ASSERT(!is_optimized_);
10438 }
10439
10440 private:
10441 JavaScriptFrame* frame_;
10442 DeoptimizedFrameInfo* deoptimized_frame_;
10443 Isolate* isolate_;
10444 bool is_optimized_;
10445 bool has_adapted_arguments_;
10446
10447 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10448};
10449
10450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451static const int kFrameDetailsFrameIdIndex = 0;
10452static const int kFrameDetailsReceiverIndex = 1;
10453static const int kFrameDetailsFunctionIndex = 2;
10454static const int kFrameDetailsArgumentCountIndex = 3;
10455static const int kFrameDetailsLocalCountIndex = 4;
10456static const int kFrameDetailsSourcePositionIndex = 5;
10457static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010458static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010459static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010460static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010461
10462// Return an array with frame details
10463// args[0]: number: break id
10464// args[1]: number: frame index
10465//
10466// The array returned contains the following information:
10467// 0: Frame id
10468// 1: Receiver
10469// 2: Function
10470// 3: Argument count
10471// 4: Local count
10472// 5: Source position
10473// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010474// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010475// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476// Arguments name, value
10477// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010478// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010479RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010480 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 ASSERT(args.length() == 2);
10482
10483 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010484 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010485 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10486 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010487 if (!maybe_check->ToObject(&check)) return maybe_check;
10488 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010489 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491
10492 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010494 if (id == StackFrame::NO_ID) {
10495 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010497 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010498
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010499 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010502 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010503 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010504 if (index < count + it.frame()->GetInlineCount()) break;
10505 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010509 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010510 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010511 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010512 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010513 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515 // Traverse the saved contexts chain to find the active context for the
10516 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010518 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 save = save->prev();
10520 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010521 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010522
10523 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525
10526 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010527 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010528 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010530 // Check for constructor frame. Inlined frames cannot be construct calls.
10531 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010532 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010533 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010535 // Get scope info and read from it for local variable information.
10536 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010537 Handle<SharedFunctionInfo> shared(function->shared());
10538 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010539 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010540 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542 // Get the locals names and values into a temporary array.
10543 //
10544 // TODO(1240907): Hide compiler-introduced stack variables
10545 // (e.g. .result)? For users of the debugger, they will probably be
10546 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010547 Handle<FixedArray> locals =
10548 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010550 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010551 int i = 0;
10552 for (; i < info.number_of_stack_slots(); ++i) {
10553 // Use the value from the stack.
10554 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010555 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010556 }
10557 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010558 // Get the context containing declarations.
10559 Handle<Context> context(
10560 Context::cast(it.frame()->context())->declaration_context());
10561 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010562 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010563 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010565 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566 }
10567 }
10568
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010569 // Check whether this frame is positioned at return. If not top
10570 // frame or if the frame is optimized it cannot be at a return.
10571 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010572 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010574 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010575
10576 // If positioned just before return find the value to be returned and add it
10577 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010579 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010580 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010581 Address internal_frame_sp = NULL;
10582 while (!it2.done()) {
10583 if (it2.frame()->is_internal()) {
10584 internal_frame_sp = it2.frame()->sp();
10585 } else {
10586 if (it2.frame()->is_java_script()) {
10587 if (it2.frame()->id() == it.frame()->id()) {
10588 // The internal frame just before the JavaScript frame contains the
10589 // value to return on top. A debug break at return will create an
10590 // internal frame to store the return value (eax/rax/r0) before
10591 // entering the debug break exit frame.
10592 if (internal_frame_sp != NULL) {
10593 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010594 Handle<Object>(Memory::Object_at(internal_frame_sp),
10595 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010596 break;
10597 }
10598 }
10599 }
10600
10601 // Indicate that the previous frame was not an internal frame.
10602 internal_frame_sp = NULL;
10603 }
10604 it2.Advance();
10605 }
10606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607
10608 // Now advance to the arguments adapter frame (if any). It contains all
10609 // the provided parameters whereas the function frame always have the number
10610 // of arguments matching the functions parameters. The rest of the
10611 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010612 if (it.frame()->has_adapted_arguments()) {
10613 it.AdvanceToArgumentsFrame();
10614 frame_inspector.SetArgumentsFrame(it.frame());
10615 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616
10617 // Find the number of arguments to fill. At least fill the number of
10618 // parameters for the function and fill more if more parameters are provided.
10619 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010620 if (argument_count < frame_inspector.GetParametersCount()) {
10621 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010623#ifdef DEBUG
10624 if (it.frame()->is_optimized()) {
10625 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10626 }
10627#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628
10629 // Calculate the size of the result.
10630 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010631 2 * (argument_count + info.NumberOfLocals()) +
10632 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010633 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634
10635 // Add the frame id.
10636 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10637
10638 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010639 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640
10641 // Add the arguments count.
10642 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10643
10644 // Add the locals count
10645 details->set(kFrameDetailsLocalCountIndex,
10646 Smi::FromInt(info.NumberOfLocals()));
10647
10648 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010649 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10651 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010652 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653 }
10654
10655 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010656 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010657
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010658 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010659 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010660
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010661 // Add flags to indicate information on whether this frame is
10662 // bit 0: invoked in the debugger context.
10663 // bit 1: optimized frame.
10664 // bit 2: inlined in optimized frame
10665 int flags = 0;
10666 if (*save->context() == *isolate->debug()->debug_context()) {
10667 flags |= 1 << 0;
10668 }
10669 if (it.frame()->is_optimized()) {
10670 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010671 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010672 }
10673 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010674
10675 // Fill the dynamic part.
10676 int details_index = kFrameDetailsFirstDynamicIndex;
10677
10678 // Add arguments name and value.
10679 for (int i = 0; i < argument_count; i++) {
10680 // Name of the argument.
10681 if (i < info.number_of_parameters()) {
10682 details->set(details_index++, *info.parameter_name(i));
10683 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010684 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010685 }
10686
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010687 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010688 if (i < it.frame()->ComputeParametersCount()) {
10689 // Get the value from the stack.
10690 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010692 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010693 }
10694 }
10695
10696 // Add locals name and value from the temporary copy from the function frame.
10697 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10698 details->set(details_index++, locals->get(i));
10699 }
10700
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010701 // Add the value being returned.
10702 if (at_return) {
10703 details->set(details_index++, *return_value);
10704 }
10705
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 // Add the receiver (same as in function frame).
10707 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10708 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010710 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10711 // If the receiver is not a JSObject and the function is not a
10712 // builtin or strict-mode we have hit an optimization where a
10713 // value object is not converted into a wrapped JS objects. To
10714 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010715 // by creating correct wrapper object based on the calling frame's
10716 // global context.
10717 it.Advance();
10718 Handle<Context> calling_frames_global_context(
10719 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010720 receiver =
10721 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010722 }
10723 details->set(kFrameDetailsReceiverIndex, *receiver);
10724
10725 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010726 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010727}
10728
10729
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010730// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010731static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010732 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010733 Handle<SerializedScopeInfo> serialized_scope_info,
10734 ScopeInfo<>& scope_info,
10735 Handle<Context> context,
10736 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010737 // Fill all context locals to the context extension.
10738 for (int i = Context::MIN_CONTEXT_SLOTS;
10739 i < scope_info.number_of_context_slots();
10740 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010741 int context_index = serialized_scope_info->ContextSlotIndex(
10742 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010743
whesse@chromium.org7b260152011-06-20 15:33:18 +000010744 RETURN_IF_EMPTY_HANDLE_VALUE(
10745 isolate,
10746 SetProperty(scope_object,
10747 scope_info.context_slot_name(i),
10748 Handle<Object>(context->get(context_index), isolate),
10749 NONE,
10750 kNonStrictMode),
10751 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010752 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010753
10754 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010755}
10756
10757
10758// Create a plain JSObject which materializes the local scope for the specified
10759// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010760static Handle<JSObject> MaterializeLocalScope(
10761 Isolate* isolate,
10762 JavaScriptFrame* frame,
10763 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010764 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010765 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010766 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10767 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010768 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010769
10770 // Allocate and initialize a JSObject with all the arguments, stack locals
10771 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010772 Handle<JSObject> local_scope =
10773 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010774
10775 // First fill all parameters.
10776 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010777 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010778 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010779 SetProperty(local_scope,
10780 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010781 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010782 NONE,
10783 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010784 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010785 }
10786
10787 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010788 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010789 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010790 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010791 SetProperty(local_scope,
10792 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010793 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010794 NONE,
10795 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010796 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010797 }
10798
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010799 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10800 // Third fill all context locals.
10801 Handle<Context> frame_context(Context::cast(frame->context()));
10802 Handle<Context> function_context(frame_context->declaration_context());
10803 if (!CopyContextLocalsToScopeObject(isolate,
10804 serialized_scope_info, scope_info,
10805 function_context, local_scope)) {
10806 return Handle<JSObject>();
10807 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010808
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010809 // Finally copy any properties from the function context extension.
10810 // These will be variables introduced by eval.
10811 if (function_context->closure() == *function) {
10812 if (function_context->has_extension() &&
10813 !function_context->IsGlobalContext()) {
10814 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10815 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10816 for (int i = 0; i < keys->length(); i++) {
10817 // Names of variables introduced by eval are strings.
10818 ASSERT(keys->get(i)->IsString());
10819 Handle<String> key(String::cast(keys->get(i)));
10820 RETURN_IF_EMPTY_HANDLE_VALUE(
10821 isolate,
10822 SetProperty(local_scope,
10823 key,
10824 GetProperty(ext, key),
10825 NONE,
10826 kNonStrictMode),
10827 Handle<JSObject>());
10828 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010829 }
10830 }
10831 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010832
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010833 return local_scope;
10834}
10835
10836
10837// Create a plain JSObject which materializes the closure content for the
10838// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010839static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10840 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010841 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010842
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010843 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010844 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10845 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010846
10847 // Allocate and initialize a JSObject with all the content of theis function
10848 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 Handle<JSObject> closure_scope =
10850 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010851
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010852 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010853 if (!CopyContextLocalsToScopeObject(isolate,
10854 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010855 context, closure_scope)) {
10856 return Handle<JSObject>();
10857 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010858
10859 // Finally copy any properties from the function context extension. This will
10860 // be variables introduced by eval.
10861 if (context->has_extension()) {
10862 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010863 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010864 for (int i = 0; i < keys->length(); i++) {
10865 // Names of variables introduced by eval are strings.
10866 ASSERT(keys->get(i)->IsString());
10867 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010868 RETURN_IF_EMPTY_HANDLE_VALUE(
10869 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010870 SetProperty(closure_scope,
10871 key,
10872 GetProperty(ext, key),
10873 NONE,
10874 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010875 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010876 }
10877 }
10878
10879 return closure_scope;
10880}
10881
10882
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010883// Create a plain JSObject which materializes the scope for the specified
10884// catch context.
10885static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10886 Handle<Context> context) {
10887 ASSERT(context->IsCatchContext());
10888 Handle<String> name(String::cast(context->extension()));
10889 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10890 Handle<JSObject> catch_scope =
10891 isolate->factory()->NewJSObject(isolate->object_function());
10892 RETURN_IF_EMPTY_HANDLE_VALUE(
10893 isolate,
10894 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10895 Handle<JSObject>());
10896 return catch_scope;
10897}
10898
10899
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010900// Create a plain JSObject which materializes the block scope for the specified
10901// block context.
10902static Handle<JSObject> MaterializeBlockScope(
10903 Isolate* isolate,
10904 Handle<Context> context) {
10905 ASSERT(context->IsBlockContext());
10906 Handle<SerializedScopeInfo> serialized_scope_info(
10907 SerializedScopeInfo::cast(context->extension()));
10908 ScopeInfo<> scope_info(*serialized_scope_info);
10909
10910 // Allocate and initialize a JSObject with all the arguments, stack locals
10911 // heap locals and extension properties of the debugged function.
10912 Handle<JSObject> block_scope =
10913 isolate->factory()->NewJSObject(isolate->object_function());
10914
10915 // Fill all context locals.
10916 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10917 if (!CopyContextLocalsToScopeObject(isolate,
10918 serialized_scope_info, scope_info,
10919 context, block_scope)) {
10920 return Handle<JSObject>();
10921 }
10922 }
10923
10924 return block_scope;
10925}
10926
10927
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010928// Iterate over the actual scopes visible from a stack frame. All scopes are
10929// backed by an actual context except the local scope, which is inserted
10930// "artifically" in the context chain.
10931class ScopeIterator {
10932 public:
10933 enum ScopeType {
10934 ScopeTypeGlobal = 0,
10935 ScopeTypeLocal,
10936 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010937 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010938 ScopeTypeCatch,
10939 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010940 };
10941
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010942 ScopeIterator(Isolate* isolate,
10943 JavaScriptFrame* frame,
10944 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010945 : isolate_(isolate),
10946 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010947 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010948 function_(JSFunction::cast(frame->function())),
10949 context_(Context::cast(frame->context())),
10950 local_done_(false),
10951 at_local_(false) {
10952
10953 // Check whether the first scope is actually a local scope.
10954 if (context_->IsGlobalContext()) {
10955 // If there is a stack slot for .result then this local scope has been
10956 // created for evaluating top level code and it is not a real local scope.
10957 // Checking for the existence of .result seems fragile, but the scope info
10958 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010959 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010960 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010961 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010962 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010963 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010964 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010965 // The context_ is a block or with or catch block from the outer function.
10966 ASSERT(context_->IsWithContext() ||
10967 context_->IsCatchContext() ||
10968 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010969 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010970 }
10971 }
10972
10973 // More scopes?
10974 bool Done() { return context_.is_null(); }
10975
10976 // Move to the next scope.
10977 void Next() {
10978 // If at a local scope mark the local scope as passed.
10979 if (at_local_) {
10980 at_local_ = false;
10981 local_done_ = true;
10982
10983 // If the current context is not associated with the local scope the
10984 // current context is the next real scope, so don't move to the next
10985 // context in this case.
10986 if (context_->closure() != *function_) {
10987 return;
10988 }
10989 }
10990
10991 // The global scope is always the last in the chain.
10992 if (context_->IsGlobalContext()) {
10993 context_ = Handle<Context>();
10994 return;
10995 }
10996
10997 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010998 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010999
11000 // If passing the local scope indicate that the current scope is now the
11001 // local scope.
11002 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011003 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011004 at_local_ = true;
11005 }
11006 }
11007
11008 // Return the type of the current scope.
11009 int Type() {
11010 if (at_local_) {
11011 return ScopeTypeLocal;
11012 }
11013 if (context_->IsGlobalContext()) {
11014 ASSERT(context_->global()->IsGlobalObject());
11015 return ScopeTypeGlobal;
11016 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011017 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011018 return ScopeTypeClosure;
11019 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011020 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011021 return ScopeTypeCatch;
11022 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011023 if (context_->IsBlockContext()) {
11024 return ScopeTypeBlock;
11025 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011026 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011027 return ScopeTypeWith;
11028 }
11029
11030 // Return the JavaScript object with the content of the current scope.
11031 Handle<JSObject> ScopeObject() {
11032 switch (Type()) {
11033 case ScopeIterator::ScopeTypeGlobal:
11034 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011035 case ScopeIterator::ScopeTypeLocal:
11036 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011037 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011038 case ScopeIterator::ScopeTypeWith:
11039 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011040 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11041 case ScopeIterator::ScopeTypeCatch:
11042 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011043 case ScopeIterator::ScopeTypeClosure:
11044 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011045 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011046 case ScopeIterator::ScopeTypeBlock:
11047 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011048 }
11049 UNREACHABLE();
11050 return Handle<JSObject>();
11051 }
11052
11053 // Return the context for this scope. For the local context there might not
11054 // be an actual context.
11055 Handle<Context> CurrentContext() {
11056 if (at_local_ && context_->closure() != *function_) {
11057 return Handle<Context>();
11058 }
11059 return context_;
11060 }
11061
11062#ifdef DEBUG
11063 // Debug print of the content of the current scope.
11064 void DebugPrint() {
11065 switch (Type()) {
11066 case ScopeIterator::ScopeTypeGlobal:
11067 PrintF("Global:\n");
11068 CurrentContext()->Print();
11069 break;
11070
11071 case ScopeIterator::ScopeTypeLocal: {
11072 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011073 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011074 scope_info.Print();
11075 if (!CurrentContext().is_null()) {
11076 CurrentContext()->Print();
11077 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011078 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011079 if (extension->IsJSContextExtensionObject()) {
11080 extension->Print();
11081 }
11082 }
11083 }
11084 break;
11085 }
11086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011087 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011089 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011090 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011092 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011093 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011094 CurrentContext()->extension()->Print();
11095 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011096 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011097
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011098 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011099 PrintF("Closure:\n");
11100 CurrentContext()->Print();
11101 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011102 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011103 if (extension->IsJSContextExtensionObject()) {
11104 extension->Print();
11105 }
11106 }
11107 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011108
11109 default:
11110 UNREACHABLE();
11111 }
11112 PrintF("\n");
11113 }
11114#endif
11115
11116 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011118 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011119 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011120 Handle<JSFunction> function_;
11121 Handle<Context> context_;
11122 bool local_done_;
11123 bool at_local_;
11124
11125 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11126};
11127
11128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011129RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011131 ASSERT(args.length() == 2);
11132
11133 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011134 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011135 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11136 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011137 if (!maybe_check->ToObject(&check)) return maybe_check;
11138 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011139 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11140
11141 // Get the frame where the debugging is performed.
11142 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011143 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144 JavaScriptFrame* frame = it.frame();
11145
11146 // Count the visible scopes.
11147 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011148 for (ScopeIterator it(isolate, frame, 0);
11149 !it.Done();
11150 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011151 n++;
11152 }
11153
11154 return Smi::FromInt(n);
11155}
11156
11157
11158static const int kScopeDetailsTypeIndex = 0;
11159static const int kScopeDetailsObjectIndex = 1;
11160static const int kScopeDetailsSize = 2;
11161
11162// Return an array with scope details
11163// args[0]: number: break id
11164// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011165// args[2]: number: inlined frame index
11166// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011167//
11168// The array returned contains the following information:
11169// 0: Scope type
11170// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011171RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011172 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011173 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011174
11175 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011176 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011177 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11178 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011179 if (!maybe_check->ToObject(&check)) return maybe_check;
11180 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011181 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011182 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11183 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011184
11185 // Get the frame where the debugging is performed.
11186 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011187 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011188 JavaScriptFrame* frame = frame_it.frame();
11189
11190 // Find the requested scope.
11191 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011192 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 for (; !it.Done() && n < index; it.Next()) {
11194 n++;
11195 }
11196 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011198 }
11199
11200 // Calculate the size of the result.
11201 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011202 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011203
11204 // Fill in scope details.
11205 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011206 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011207 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011208 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011210 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011211}
11212
11213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011214RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011215 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011216 ASSERT(args.length() == 0);
11217
11218#ifdef DEBUG
11219 // Print the scopes for the top frame.
11220 StackFrameLocator locator;
11221 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011222 for (ScopeIterator it(isolate, frame, 0);
11223 !it.Done();
11224 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011225 it.DebugPrint();
11226 }
11227#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011228 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011229}
11230
11231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011232RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011233 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011234 ASSERT(args.length() == 1);
11235
11236 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011237 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011238 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11239 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011240 if (!maybe_result->ToObject(&result)) return maybe_result;
11241 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011242
11243 // Count all archived V8 threads.
11244 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011245 for (ThreadState* thread =
11246 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011247 thread != NULL;
11248 thread = thread->Next()) {
11249 n++;
11250 }
11251
11252 // Total number of threads is current thread and archived threads.
11253 return Smi::FromInt(n + 1);
11254}
11255
11256
11257static const int kThreadDetailsCurrentThreadIndex = 0;
11258static const int kThreadDetailsThreadIdIndex = 1;
11259static const int kThreadDetailsSize = 2;
11260
11261// Return an array with thread details
11262// args[0]: number: break id
11263// args[1]: number: thread index
11264//
11265// The array returned contains the following information:
11266// 0: Is current thread?
11267// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011268RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011269 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011270 ASSERT(args.length() == 2);
11271
11272 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011273 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011274 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11275 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011276 if (!maybe_check->ToObject(&check)) return maybe_check;
11277 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011278 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11279
11280 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011281 Handle<FixedArray> details =
11282 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011283
11284 // Thread index 0 is current thread.
11285 if (index == 0) {
11286 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011287 details->set(kThreadDetailsCurrentThreadIndex,
11288 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011289 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011290 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011291 } else {
11292 // Find the thread with the requested index.
11293 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011294 ThreadState* thread =
11295 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011296 while (index != n && thread != NULL) {
11297 thread = thread->Next();
11298 n++;
11299 }
11300 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011301 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011302 }
11303
11304 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011305 details->set(kThreadDetailsCurrentThreadIndex,
11306 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011307 details->set(kThreadDetailsThreadIdIndex,
11308 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011309 }
11310
11311 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011313}
11314
11315
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011316// Sets the disable break state
11317// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011318RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011319 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011320 ASSERT(args.length() == 1);
11321 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011322 isolate->debug()->set_disable_break(disable_break);
11323 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011324}
11325
11326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011327RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011328 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011329 ASSERT(args.length() == 1);
11330
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011331 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11332 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011333 // Find the number of break points
11334 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011336 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 Handle<FixedArray>::cast(break_locations));
11339}
11340
11341
11342// Set a break point in a function
11343// args[0]: function
11344// args[1]: number: break source position (within the function source)
11345// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011346RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011348 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011349 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11350 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011351 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11352 RUNTIME_ASSERT(source_position >= 0);
11353 Handle<Object> break_point_object_arg = args.at<Object>(2);
11354
11355 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011356 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11357 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011358
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011359 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011360}
11361
11362
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011363Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11364 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011365 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011366 // Iterate the heap looking for SharedFunctionInfo generated from the
11367 // script. The inner most SharedFunctionInfo containing the source position
11368 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011369 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011370 // which is found is not compiled it is compiled and the heap is iterated
11371 // again as the compilation might create inner functions from the newly
11372 // compiled function and the actual requested break point might be in one of
11373 // these functions.
11374 bool done = false;
11375 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011376 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011377 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011378 while (!done) {
11379 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011380 for (HeapObject* obj = iterator.next();
11381 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011382 if (obj->IsSharedFunctionInfo()) {
11383 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11384 if (shared->script() == *script) {
11385 // If the SharedFunctionInfo found has the requested script data and
11386 // contains the source position it is a candidate.
11387 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011388 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011389 start_position = shared->start_position();
11390 }
11391 if (start_position <= position &&
11392 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011393 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011394 // candidate this is the new candidate.
11395 if (target.is_null()) {
11396 target_start_position = start_position;
11397 target = shared;
11398 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011399 if (target_start_position == start_position &&
11400 shared->end_position() == target->end_position()) {
11401 // If a top-level function contain only one function
11402 // declartion the source for the top-level and the function is
11403 // the same. In that case prefer the non top-level function.
11404 if (!shared->is_toplevel()) {
11405 target_start_position = start_position;
11406 target = shared;
11407 }
11408 } else if (target_start_position <= start_position &&
11409 shared->end_position() <= target->end_position()) {
11410 // This containment check includes equality as a function inside
11411 // a top-level function can share either start or end position
11412 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011413 target_start_position = start_position;
11414 target = shared;
11415 }
11416 }
11417 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011418 }
11419 }
11420 }
11421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011422 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011423 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 }
11425
11426 // If the candidate found is compiled we are done. NOTE: when lazy
11427 // compilation of inner functions is introduced some additional checking
11428 // needs to be done here to compile inner functions.
11429 done = target->is_compiled();
11430 if (!done) {
11431 // If the candidate is not compiled compile it to reveal any inner
11432 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011433 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011434 }
11435 }
11436
11437 return *target;
11438}
11439
11440
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011441// Changes the state of a break point in a script and returns source position
11442// where break point was set. NOTE: Regarding performance see the NOTE for
11443// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011444// args[0]: script to set break point in
11445// args[1]: number: break source position (within the script source)
11446// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011447RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011448 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011449 ASSERT(args.length() == 3);
11450 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11451 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11452 RUNTIME_ASSERT(source_position >= 0);
11453 Handle<Object> break_point_object_arg = args.at<Object>(2);
11454
11455 // Get the script from the script wrapper.
11456 RUNTIME_ASSERT(wrapper->value()->IsScript());
11457 Handle<Script> script(Script::cast(wrapper->value()));
11458
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011459 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011460 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011461 if (!result->IsUndefined()) {
11462 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11463 // Find position within function. The script position might be before the
11464 // source position of the first function.
11465 int position;
11466 if (shared->start_position() > source_position) {
11467 position = 0;
11468 } else {
11469 position = source_position - shared->start_position();
11470 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011472 position += shared->start_position();
11473 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011474 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011476}
11477
11478
11479// Clear a break point
11480// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011481RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011482 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011483 ASSERT(args.length() == 1);
11484 Handle<Object> break_point_object_arg = args.at<Object>(0);
11485
11486 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011487 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011489 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011490}
11491
11492
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011493// Change the state of break on exceptions.
11494// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11495// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011496RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011497 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011498 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011499 RUNTIME_ASSERT(args[0]->IsNumber());
11500 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011501
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011502 // If the number doesn't match an enum value, the ChangeBreakOnException
11503 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011504 ExceptionBreakType type =
11505 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011506 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 isolate->debug()->ChangeBreakOnException(type, enable);
11508 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011509}
11510
11511
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011512// Returns the state of break on exceptions
11513// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011514RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011516 ASSERT(args.length() == 1);
11517 RUNTIME_ASSERT(args[0]->IsNumber());
11518
11519 ExceptionBreakType type =
11520 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011521 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011522 return Smi::FromInt(result);
11523}
11524
11525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011526// Prepare for stepping
11527// args[0]: break id for checking execution state
11528// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011529// args[2]: number of times to perform the step, for step out it is the number
11530// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011531RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011532 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011533 ASSERT(args.length() == 3);
11534 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011535 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011536 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11537 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011538 if (!maybe_check->ToObject(&check)) return maybe_check;
11539 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542 }
11543
11544 // Get the step action and check validity.
11545 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11546 if (step_action != StepIn &&
11547 step_action != StepNext &&
11548 step_action != StepOut &&
11549 step_action != StepInMin &&
11550 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011551 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011552 }
11553
11554 // Get the number of steps.
11555 int step_count = NumberToInt32(args[2]);
11556 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011558 }
11559
ager@chromium.orga1645e22009-09-09 19:27:10 +000011560 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011561 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011563 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011564 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11565 step_count);
11566 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011567}
11568
11569
11570// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011571RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011572 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011573 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 isolate->debug()->ClearStepping();
11575 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011576}
11577
11578
11579// Creates a copy of the with context chain. The copy of the context chain is
11580// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011581static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011582 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011583 Handle<Context> current,
11584 Handle<Context> base) {
11585 // At the end of the chain. Return the base context to link to.
11586 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11587 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011588 }
11589
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011590 // Recursively copy the with and catch contexts.
11591 HandleScope scope(isolate);
11592 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011593 Handle<Context> new_previous =
11594 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011595 Handle<Context> new_current;
11596 if (current->IsCatchContext()) {
11597 Handle<String> name(String::cast(current->extension()));
11598 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11599 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011600 isolate->factory()->NewCatchContext(function,
11601 new_previous,
11602 name,
11603 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011604 } else if (current->IsBlockContext()) {
11605 Handle<SerializedScopeInfo> scope_info(
11606 SerializedScopeInfo::cast(current->extension()));
11607 new_current =
11608 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011609 // Copy context slots.
11610 int num_context_slots = scope_info->NumberOfContextSlots();
11611 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11612 new_current->set(i, current->get(i));
11613 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011614 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011615 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011616 Handle<JSObject> extension(JSObject::cast(current->extension()));
11617 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011618 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011619 }
11620 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011621}
11622
11623
11624// Helper function to find or create the arguments object for
11625// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626static Handle<Object> GetArgumentsObject(Isolate* isolate,
11627 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011628 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011629 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011630 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631 const ScopeInfo<>* sinfo,
11632 Handle<Context> function_context) {
11633 // Try to find the value of 'arguments' to pass as parameter. If it is not
11634 // found (that is the debugged function does not reference 'arguments' and
11635 // does not support eval) then create an 'arguments' object.
11636 int index;
11637 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011639 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011641 }
11642 }
11643
11644 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11646 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011648 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011649 }
11650 }
11651
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011652 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11653
11654 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 Handle<JSObject> arguments =
11656 isolate->factory()->NewArgumentsObject(function, length);
11657 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011658
11659 AssertNoAllocation no_gc;
11660 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011661 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011662 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011663 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011664 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011665 return arguments;
11666}
11667
11668
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669static const char kSourceStr[] =
11670 "(function(arguments,__source__){return eval(__source__);})";
11671
11672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011673// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011674// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011675// extension part has all the parameters and locals of the function on the
11676// stack frame. A function which calls eval with the code to evaluate is then
11677// compiled in this context and called in this context. As this context
11678// replaces the context of the function on the stack frame a new (empty)
11679// function is created as well to be used as the closure for the context.
11680// This function and the context acts as replacements for the function on the
11681// stack frame presenting the same view of the values of parameters and
11682// local variables as if the piece of JavaScript was evaluated at the point
11683// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011684RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011685 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011686
11687 // Check the execution state and decode arguments frame and source to be
11688 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011689 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011690 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011691 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11692 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011693 if (!maybe_check_result->ToObject(&check_result)) {
11694 return maybe_check_result;
11695 }
11696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011697 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011698 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11699 CONVERT_ARG_CHECKED(String, source, 3);
11700 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11701 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011702
11703 // Handle the processing of break.
11704 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011705
11706 // Get the frame where the debugging is performed.
11707 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011708 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011709 JavaScriptFrame* frame = it.frame();
11710 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011711 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011712 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011713
11714 // Traverse the saved contexts chain to find the active context for the
11715 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011717 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011718 save = save->prev();
11719 }
11720 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011721 SaveContext savex(isolate);
11722 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723
11724 // Create the (empty) function replacing the function on the stack frame for
11725 // the purpose of evaluating in the context created below. It is important
11726 // that this function does not describe any parameters and local variables
11727 // in the context. If it does then this will cause problems with the lookup
11728 // in Context::Lookup, where context slots for parameters and local variables
11729 // are looked at before the extension object.
11730 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011731 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11732 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011733 go_between->set_context(function->context());
11734#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011735 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011736 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11737 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11738#endif
11739
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011740 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011741 Handle<JSObject> local_scope = MaterializeLocalScope(
11742 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011743 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011744
11745 // Allocate a new context for the debug evaluation and set the extension
11746 // object build.
11747 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011748 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11749 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011750 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011751 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011752 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011753 Handle<Context> function_context;
11754 // Get the function's context if it has one.
11755 if (scope_info->HasHeapAllocatedLocals()) {
11756 function_context = Handle<Context>(frame_context->declaration_context());
11757 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011758 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011759
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011760 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011761 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011762 context =
11763 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011764 }
11765
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011766 // Wrap the evaluation statement in a new function compiled in the newly
11767 // created context. The function has one parameter which has to be called
11768 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011769 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011770 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 isolate->factory()->NewStringFromAscii(
11774 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011775
11776 // Currently, the eval code will be executed in non-strict mode,
11777 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011778 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011779 Compiler::CompileEval(function_source,
11780 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011781 context->IsGlobalContext(),
11782 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011783 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011785 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011786
11787 // Invoke the result of the compilation to get the evaluation function.
11788 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011789 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790 Handle<Object> evaluation_function =
11791 Execution::Call(compiled_function, receiver, 0, NULL,
11792 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011793 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011794
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011795 Handle<Object> arguments = GetArgumentsObject(isolate,
11796 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011797 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011798 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799
11800 // Invoke the evaluation function and return the result.
11801 const int argc = 2;
11802 Object** argv[argc] = { arguments.location(),
11803 Handle<Object>::cast(source).location() };
11804 Handle<Object> result =
11805 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11806 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011807 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011808
11809 // Skip the global proxy as it has no properties and always delegates to the
11810 // real global object.
11811 if (result->IsJSGlobalProxy()) {
11812 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11813 }
11814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011815 return *result;
11816}
11817
11818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011819RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011820 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011821
11822 // Check the execution state and decode arguments frame and source to be
11823 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011824 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011825 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011826 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11827 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011828 if (!maybe_check_result->ToObject(&check_result)) {
11829 return maybe_check_result;
11830 }
11831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011832 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011833 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011834 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011835
11836 // Handle the processing of break.
11837 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838
11839 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011840 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011842 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011843 top = top->prev();
11844 }
11845 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011846 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847 }
11848
11849 // Get the global context now set to the top context from before the
11850 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011851 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011853 bool is_global = true;
11854
11855 if (additional_context->IsJSObject()) {
11856 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011857 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11858 isolate->factory()->empty_string(),
11859 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011860 go_between->set_context(*context);
11861 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011862 isolate->factory()->NewFunctionContext(
11863 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011864 context->set_extension(JSObject::cast(*additional_context));
11865 is_global = false;
11866 }
11867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011868 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011869 // Currently, the eval code will be executed in non-strict mode,
11870 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011871 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011872 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011873 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011874 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011875 Handle<JSFunction>(
11876 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11877 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878
11879 // Invoke the result of the compilation to get the evaluation function.
11880 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011882 Handle<Object> result =
11883 Execution::Call(compiled_function, receiver, 0, NULL,
11884 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011885 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011886 return *result;
11887}
11888
11889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011890RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011891 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011892 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011895 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896
11897 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011898 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011899 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11900 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11901 // because using
11902 // instances->set(i, *GetScriptWrapper(script))
11903 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11904 // already have deferenced the instances handle.
11905 Handle<JSValue> wrapper = GetScriptWrapper(script);
11906 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907 }
11908
11909 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910 Handle<JSObject> result =
11911 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011912 Handle<JSArray>::cast(result)->SetContent(*instances);
11913 return *result;
11914}
11915
11916
11917// Helper function used by Runtime_DebugReferencedBy below.
11918static int DebugReferencedBy(JSObject* target,
11919 Object* instance_filter, int max_references,
11920 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921 JSFunction* arguments_function) {
11922 NoHandleAllocation ha;
11923 AssertNoAllocation no_alloc;
11924
11925 // Iterate the heap.
11926 int count = 0;
11927 JSObject* last = NULL;
11928 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011929 HeapObject* heap_obj = NULL;
11930 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011931 (max_references == 0 || count < max_references)) {
11932 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933 if (heap_obj->IsJSObject()) {
11934 // Skip context extension objects and argument arrays as these are
11935 // checked in the context of functions using them.
11936 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011937 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011938 obj->map()->constructor() == arguments_function) {
11939 continue;
11940 }
11941
11942 // Check if the JS object has a reference to the object looked for.
11943 if (obj->ReferencesObject(target)) {
11944 // Check instance filter if supplied. This is normally used to avoid
11945 // references from mirror objects (see Runtime_IsInPrototypeChain).
11946 if (!instance_filter->IsUndefined()) {
11947 Object* V = obj;
11948 while (true) {
11949 Object* prototype = V->GetPrototype();
11950 if (prototype->IsNull()) {
11951 break;
11952 }
11953 if (instance_filter == prototype) {
11954 obj = NULL; // Don't add this object.
11955 break;
11956 }
11957 V = prototype;
11958 }
11959 }
11960
11961 if (obj != NULL) {
11962 // Valid reference found add to instance array if supplied an update
11963 // count.
11964 if (instances != NULL && count < instances_size) {
11965 instances->set(count, obj);
11966 }
11967 last = obj;
11968 count++;
11969 }
11970 }
11971 }
11972 }
11973
11974 // Check for circular reference only. This can happen when the object is only
11975 // referenced from mirrors and has a circular reference in which case the
11976 // object is not really alive and would have been garbage collected if not
11977 // referenced from the mirror.
11978 if (count == 1 && last == target) {
11979 count = 0;
11980 }
11981
11982 // Return the number of referencing objects found.
11983 return count;
11984}
11985
11986
11987// Scan the heap for objects with direct references to an object
11988// args[0]: the object to find references to
11989// args[1]: constructor function for instances to exclude (Mirror)
11990// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011991RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011992 ASSERT(args.length() == 3);
11993
11994 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011995 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996
11997 // Check parameters.
11998 CONVERT_CHECKED(JSObject, target, args[0]);
11999 Object* instance_filter = args[1];
12000 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12001 instance_filter->IsJSObject());
12002 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12003 RUNTIME_ASSERT(max_references >= 0);
12004
12005 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012006 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012007 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012008 JSFunction* arguments_function =
12009 JSFunction::cast(arguments_boilerplate->map()->constructor());
12010
12011 // Get the number of referencing objects.
12012 int count;
12013 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012014 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015
12016 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012017 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012019 if (!maybe_object->ToObject(&object)) return maybe_object;
12020 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012021 FixedArray* instances = FixedArray::cast(object);
12022
12023 // Fill the referencing objects.
12024 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012025 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012026
12027 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012028 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012029 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12030 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012031 if (!maybe_result->ToObject(&result)) return maybe_result;
12032 }
12033 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012034 return result;
12035}
12036
12037
12038// Helper function used by Runtime_DebugConstructedBy below.
12039static int DebugConstructedBy(JSFunction* constructor, int max_references,
12040 FixedArray* instances, int instances_size) {
12041 AssertNoAllocation no_alloc;
12042
12043 // Iterate the heap.
12044 int count = 0;
12045 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012046 HeapObject* heap_obj = NULL;
12047 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012048 (max_references == 0 || count < max_references)) {
12049 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050 if (heap_obj->IsJSObject()) {
12051 JSObject* obj = JSObject::cast(heap_obj);
12052 if (obj->map()->constructor() == constructor) {
12053 // Valid reference found add to instance array if supplied an update
12054 // count.
12055 if (instances != NULL && count < instances_size) {
12056 instances->set(count, obj);
12057 }
12058 count++;
12059 }
12060 }
12061 }
12062
12063 // Return the number of referencing objects found.
12064 return count;
12065}
12066
12067
12068// Scan the heap for objects constructed by a specific function.
12069// args[0]: the constructor to find instances of
12070// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012071RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012072 ASSERT(args.length() == 2);
12073
12074 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012075 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076
12077 // Check parameters.
12078 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12079 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12080 RUNTIME_ASSERT(max_references >= 0);
12081
12082 // Get the number of referencing objects.
12083 int count;
12084 count = DebugConstructedBy(constructor, max_references, NULL, 0);
12085
12086 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012087 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012088 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012089 if (!maybe_object->ToObject(&object)) return maybe_object;
12090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012091 FixedArray* instances = FixedArray::cast(object);
12092
12093 // Fill the referencing objects.
12094 count = DebugConstructedBy(constructor, max_references, instances, count);
12095
12096 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012097 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012098 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12099 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012100 if (!maybe_result->ToObject(&result)) return maybe_result;
12101 }
12102 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012103 return result;
12104}
12105
12106
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012107// Find the effective prototype object as returned by __proto__.
12108// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012109RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110 ASSERT(args.length() == 1);
12111
12112 CONVERT_CHECKED(JSObject, obj, args[0]);
12113
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012114 // Use the __proto__ accessor.
12115 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012116}
12117
12118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012119RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012120 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012122 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123}
12124
12125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012126RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012127#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012128 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012129 ASSERT(args.length() == 1);
12130 // Get the function and make sure it is compiled.
12131 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012132 Handle<SharedFunctionInfo> shared(func->shared());
12133 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012134 return Failure::Exception();
12135 }
12136 func->code()->PrintLn();
12137#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012138 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012139}
ager@chromium.org9085a012009-05-11 19:22:57 +000012140
12141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012142RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012143#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012144 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012145 ASSERT(args.length() == 1);
12146 // Get the function and make sure it is compiled.
12147 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012148 Handle<SharedFunctionInfo> shared(func->shared());
12149 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012150 return Failure::Exception();
12151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012152 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012153#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012154 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012155}
12156
12157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012158RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012159 NoHandleAllocation ha;
12160 ASSERT(args.length() == 1);
12161
12162 CONVERT_CHECKED(JSFunction, f, args[0]);
12163 return f->shared()->inferred_name();
12164}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012165
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012166
12167static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012169 AssertNoAllocation no_allocations;
12170
12171 int counter = 0;
12172 int buffer_size = buffer->length();
12173 HeapIterator iterator;
12174 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
12175 ASSERT(obj != NULL);
12176 if (!obj->IsSharedFunctionInfo()) {
12177 continue;
12178 }
12179 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12180 if (shared->script() != script) {
12181 continue;
12182 }
12183 if (counter < buffer_size) {
12184 buffer->set(counter, shared);
12185 }
12186 counter++;
12187 }
12188 return counter;
12189}
12190
12191// For a script finds all SharedFunctionInfo's in the heap that points
12192// to this script. Returns JSArray of SharedFunctionInfo wrapped
12193// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012194RUNTIME_FUNCTION(MaybeObject*,
12195 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012196 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012197 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012198 CONVERT_CHECKED(JSValue, script_value, args[0]);
12199
12200 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12201
12202 const int kBufferSize = 32;
12203
12204 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012205 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012206 int number = FindSharedFunctionInfosForScript(*script, *array);
12207 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012208 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012209 FindSharedFunctionInfosForScript(*script, *array);
12210 }
12211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012212 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012213 result->set_length(Smi::FromInt(number));
12214
12215 LiveEdit::WrapSharedFunctionInfos(result);
12216
12217 return *result;
12218}
12219
12220// For a script calculates compilation information about all its functions.
12221// The script source is explicitly specified by the second argument.
12222// The source of the actual script is not used, however it is important that
12223// all generated code keeps references to this particular instance of script.
12224// Returns a JSArray of compilation infos. The array is ordered so that
12225// each function with all its descendant is always stored in a continues range
12226// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012227RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012228 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012229 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012230 CONVERT_CHECKED(JSValue, script, args[0]);
12231 CONVERT_ARG_CHECKED(String, source, 1);
12232 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12233
12234 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012236 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012237 return Failure::Exception();
12238 }
12239
12240 return result;
12241}
12242
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012243// Changes the source of the script to a new_source.
12244// If old_script_name is provided (i.e. is a String), also creates a copy of
12245// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012246RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012247 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012248 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012249 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12250 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012251 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012252
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012253 CONVERT_CHECKED(Script, original_script_pointer,
12254 original_script_value->value());
12255 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012256
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012257 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12258 new_source,
12259 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012260
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012261 if (old_script->IsScript()) {
12262 Handle<Script> script_handle(Script::cast(old_script));
12263 return *(GetScriptWrapper(script_handle));
12264 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012265 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012266 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012267}
12268
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012270RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012271 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012272 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012273 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12274 return LiveEdit::FunctionSourceUpdated(shared_info);
12275}
12276
12277
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012278// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012279RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012280 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012281 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012282 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12283 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12284
ager@chromium.orgac091b72010-05-05 07:34:42 +000012285 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012286}
12287
12288// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012289RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012290 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012291 HandleScope scope(isolate);
12292 Handle<Object> function_object(args[0], isolate);
12293 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012294
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012295 if (function_object->IsJSValue()) {
12296 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12297 if (script_object->IsJSValue()) {
12298 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012299 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012300 }
12301
12302 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12303 } else {
12304 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12305 // and we check it in this function.
12306 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012308 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012309}
12310
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012311
12312// In a code of a parent function replaces original function as embedded object
12313// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012314RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012315 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012316 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012317
12318 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12319 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12320 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12321
12322 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12323 subst_wrapper);
12324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012325 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012326}
12327
12328
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012329// Updates positions of a shared function info (first parameter) according
12330// to script source change. Text change is described in second parameter as
12331// array of groups of 3 numbers:
12332// (change_begin, change_end, change_end_new_position).
12333// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012334RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012335 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012336 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012337 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12338 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12339
ager@chromium.orgac091b72010-05-05 07:34:42 +000012340 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012341}
12342
12343
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012344// For array of SharedFunctionInfo's (each wrapped in JSValue)
12345// checks that none of them have activations on stacks (of any thread).
12346// Returns array of the same length with corresponding results of
12347// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012348RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012349 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012350 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012351 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012352 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012353
ager@chromium.org357bf652010-04-12 11:30:10 +000012354 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012355}
12356
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012357// Compares 2 strings line-by-line, then token-wise and returns diff in form
12358// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12359// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012360RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012361 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012362 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012363 CONVERT_ARG_CHECKED(String, s1, 0);
12364 CONVERT_ARG_CHECKED(String, s2, 1);
12365
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012366 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012367}
12368
12369
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012370// A testing entry. Returns statement position which is the closest to
12371// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012372RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012373 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012374 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012375 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12376 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12377
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012378 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012379
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012380 if (code->kind() != Code::FUNCTION &&
12381 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012382 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012383 }
12384
12385 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012386 int closest_pc = 0;
12387 int distance = kMaxInt;
12388 while (!it.done()) {
12389 int statement_position = static_cast<int>(it.rinfo()->data());
12390 // Check if this break point is closer that what was previously found.
12391 if (source_position <= statement_position &&
12392 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012393 closest_pc =
12394 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012395 distance = statement_position - source_position;
12396 // Check whether we can't get any closer.
12397 if (distance == 0) break;
12398 }
12399 it.next();
12400 }
12401
12402 return Smi::FromInt(closest_pc);
12403}
12404
12405
ager@chromium.org357bf652010-04-12 11:30:10 +000012406// Calls specified function with or without entering the debugger.
12407// This is used in unit tests to run code as if debugger is entered or simply
12408// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012409RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012410 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012411 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012412 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12413 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12414
12415 Handle<Object> result;
12416 bool pending_exception;
12417 {
12418 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012419 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012420 &pending_exception);
12421 } else {
12422 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012423 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012424 &pending_exception);
12425 }
12426 }
12427 if (!pending_exception) {
12428 return *result;
12429 } else {
12430 return Failure::Exception();
12431 }
12432}
12433
12434
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012435// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012436RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012437 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012438 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012439 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12440 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012441 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012442}
12443
12444
12445// Performs a GC.
12446// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012447RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012448 isolate->heap()->CollectAllGarbage(true);
12449 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012450}
12451
12452
12453// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012454RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012455 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012456 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012457 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012458 }
12459 return Smi::FromInt(usage);
12460}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012461
12462
12463// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012464RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012465#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012467#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012468 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012469#endif
12470}
12471
12472
12473// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012474RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012475#ifdef LIVE_OBJECT_LIST
12476 return LiveObjectList::Capture();
12477#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012478 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012479#endif
12480}
12481
12482
12483// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012484RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012485#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012486 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012487 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012488 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012489#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012490 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012491#endif
12492}
12493
12494
12495// Generates the response to a debugger request for a dump of the objects
12496// contained in the difference between the captured live object lists
12497// specified by id1 and id2.
12498// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12499// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012500RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012501#ifdef LIVE_OBJECT_LIST
12502 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012503 CONVERT_SMI_ARG_CHECKED(id1, 0);
12504 CONVERT_SMI_ARG_CHECKED(id2, 1);
12505 CONVERT_SMI_ARG_CHECKED(start, 2);
12506 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012507 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12508 EnterDebugger enter_debugger;
12509 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12510#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012511 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012512#endif
12513}
12514
12515
12516// Gets the specified object as requested by the debugger.
12517// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012518RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012519#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012520 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012521 Object* result = LiveObjectList::GetObj(obj_id);
12522 return result;
12523#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012525#endif
12526}
12527
12528
12529// Gets the obj id for the specified address if valid.
12530// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012531RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012532#ifdef LIVE_OBJECT_LIST
12533 HandleScope scope;
12534 CONVERT_ARG_CHECKED(String, address, 0);
12535 Object* result = LiveObjectList::GetObjId(address);
12536 return result;
12537#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012538 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012539#endif
12540}
12541
12542
12543// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012544RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012545#ifdef LIVE_OBJECT_LIST
12546 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012547 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012548 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12549 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12550 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12551 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12552 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12553
12554 Handle<JSObject> instance_filter;
12555 if (args[1]->IsJSObject()) {
12556 instance_filter = args.at<JSObject>(1);
12557 }
12558 bool verbose = false;
12559 if (args[2]->IsBoolean()) {
12560 verbose = args[2]->IsTrue();
12561 }
12562 int start = 0;
12563 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012564 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012565 }
12566 int limit = Smi::kMaxValue;
12567 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012568 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012569 }
12570
12571 return LiveObjectList::GetObjRetainers(obj_id,
12572 instance_filter,
12573 verbose,
12574 start,
12575 limit,
12576 filter_obj);
12577#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012579#endif
12580}
12581
12582
12583// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012584RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012585#ifdef LIVE_OBJECT_LIST
12586 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012587 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12588 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012589 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12590
12591 Handle<JSObject> instance_filter;
12592 if (args[2]->IsJSObject()) {
12593 instance_filter = args.at<JSObject>(2);
12594 }
12595
12596 Object* result =
12597 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12598 return result;
12599#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012600 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012601#endif
12602}
12603
12604
12605// Generates the response to a debugger request for a list of all
12606// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012607RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012608#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012609 CONVERT_SMI_ARG_CHECKED(start, 0);
12610 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012611 return LiveObjectList::Info(start, count);
12612#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012613 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012614#endif
12615}
12616
12617
12618// Gets a dump of the specified object as requested by the debugger.
12619// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012620RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012621#ifdef LIVE_OBJECT_LIST
12622 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012623 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012624 Object* result = LiveObjectList::PrintObj(obj_id);
12625 return result;
12626#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012627 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012628#endif
12629}
12630
12631
12632// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012633RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012634#ifdef LIVE_OBJECT_LIST
12635 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012636 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012637#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012638 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012639#endif
12640}
12641
12642
12643// Generates the response to a debugger request for a summary of the types
12644// of objects in the difference between the captured live object lists
12645// specified by id1 and id2.
12646// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12647// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012648RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012649#ifdef LIVE_OBJECT_LIST
12650 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012651 CONVERT_SMI_ARG_CHECKED(id1, 0);
12652 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012653 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12654
12655 EnterDebugger enter_debugger;
12656 return LiveObjectList::Summarize(id1, id2, filter_obj);
12657#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012658 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012659#endif
12660}
12661
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012662#endif // ENABLE_DEBUGGER_SUPPORT
12663
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012665RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012666 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012667 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012668 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012669}
12670
12671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012672RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012673 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012674 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012675 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012676}
12677
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012679// Finds the script object from the script data. NOTE: This operation uses
12680// heap traversal to find the function generated for the source position
12681// for the requested break point. For lazily compiled functions several heap
12682// traversals might be required rendering this operation as a rather slow
12683// operation. However for setting break points which is normally done through
12684// some kind of user interaction the performance is not crucial.
12685static Handle<Object> Runtime_GetScriptFromScriptName(
12686 Handle<String> script_name) {
12687 // Scan the heap for Script objects to find the script with the requested
12688 // script data.
12689 Handle<Script> script;
12690 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012691 HeapObject* obj = NULL;
12692 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012693 // If a script is found check if it has the script data requested.
12694 if (obj->IsScript()) {
12695 if (Script::cast(obj)->name()->IsString()) {
12696 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12697 script = Handle<Script>(Script::cast(obj));
12698 }
12699 }
12700 }
12701 }
12702
12703 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012705
12706 // Return the script found.
12707 return GetScriptWrapper(script);
12708}
12709
12710
12711// Get the script object from script data. NOTE: Regarding performance
12712// see the NOTE for GetScriptFromScriptData.
12713// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012715 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012716
12717 ASSERT(args.length() == 1);
12718
12719 CONVERT_CHECKED(String, script_name, args[0]);
12720
12721 // Find the requested script.
12722 Handle<Object> result =
12723 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12724 return *result;
12725}
12726
12727
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012728// Determines whether the given stack frame should be displayed in
12729// a stack trace. The caller is the error constructor that asked
12730// for the stack trace to be collected. The first time a construct
12731// call to this function is encountered it is skipped. The seen_caller
12732// in/out parameter is used to remember if the caller has been seen
12733// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012734static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12735 Object* caller,
12736 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012737 // Only display JS frames.
12738 if (!raw_frame->is_java_script())
12739 return false;
12740 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12741 Object* raw_fun = frame->function();
12742 // Not sure when this can happen but skip it just in case.
12743 if (!raw_fun->IsJSFunction())
12744 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012745 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012746 *seen_caller = true;
12747 return false;
12748 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012749 // Skip all frames until we've seen the caller.
12750 if (!(*seen_caller)) return false;
12751 // Also, skip the most obvious builtin calls. We recognize builtins
12752 // as (1) functions called with the builtins object as the receiver and
12753 // as (2) functions from native scripts called with undefined as the
12754 // receiver (direct calls to helper functions in the builtins
12755 // code). Some builtin calls (such as Number.ADD which is invoked
12756 // using 'call') are very difficult to recognize so we're leaving
12757 // them in for now.
12758 if (frame->receiver()->IsJSBuiltinsObject()) {
12759 return false;
12760 }
12761 JSFunction* fun = JSFunction::cast(raw_fun);
12762 Object* raw_script = fun->shared()->script();
12763 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12764 int script_type = Script::cast(raw_script)->type()->value();
12765 return script_type != Script::TYPE_NATIVE;
12766 }
12767 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012768}
12769
12770
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012771// Collect the raw data for a stack trace. Returns an array of 4
12772// element segments each containing a receiver, function, code and
12773// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012774RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012775 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012776 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012777 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012779 HandleScope scope(isolate);
12780 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012781
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012782 limit = Max(limit, 0); // Ensure that limit is not negative.
12783 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012784 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012785 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012786
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012787 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012788 // If the caller parameter is a function we skip frames until we're
12789 // under it before starting to collect.
12790 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012791 int cursor = 0;
12792 int frames_seen = 0;
12793 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012794 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012795 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012796 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012797 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012798 // Set initial size to the maximum inlining level + 1 for the outermost
12799 // function.
12800 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012801 frame->Summarize(&frames);
12802 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012803 if (cursor + 4 > elements->length()) {
12804 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12805 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012806 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012807 for (int i = 0; i < cursor; i++) {
12808 new_elements->set(i, elements->get(i));
12809 }
12810 elements = new_elements;
12811 }
12812 ASSERT(cursor + 4 <= elements->length());
12813
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012814 Handle<Object> recv = frames[i].receiver();
12815 Handle<JSFunction> fun = frames[i].function();
12816 Handle<Code> code = frames[i].code();
12817 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012818 elements->set(cursor++, *recv);
12819 elements->set(cursor++, *fun);
12820 elements->set(cursor++, *code);
12821 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012822 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012823 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012824 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012825 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012826 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012827 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012828 return *result;
12829}
12830
12831
ager@chromium.org3811b432009-10-28 14:53:37 +000012832// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012833RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012834 ASSERT_EQ(args.length(), 0);
12835
12836 NoHandleAllocation ha;
12837
12838 const char* version_string = v8::V8::GetVersion();
12839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012840 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12841 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012842}
12843
12844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012845RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012846 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012847 OS::PrintError("abort: %s\n",
12848 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012849 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012850 OS::Abort();
12851 UNREACHABLE();
12852 return NULL;
12853}
12854
12855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012856RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012857 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012858 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012859 Object* key = args[1];
12860
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012861 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012862 Object* o = cache->get(finger_index);
12863 if (o == key) {
12864 // The fastest case: hit the same place again.
12865 return cache->get(finger_index + 1);
12866 }
12867
12868 for (int i = finger_index - 2;
12869 i >= JSFunctionResultCache::kEntriesIndex;
12870 i -= 2) {
12871 o = cache->get(i);
12872 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012873 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012874 return cache->get(i + 1);
12875 }
12876 }
12877
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012878 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012879 ASSERT(size <= cache->length());
12880
12881 for (int i = size - 2; i > finger_index; i -= 2) {
12882 o = cache->get(i);
12883 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012884 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012885 return cache->get(i + 1);
12886 }
12887 }
12888
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012889 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012890 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012891
12892 Handle<JSFunctionResultCache> cache_handle(cache);
12893 Handle<Object> key_handle(key);
12894 Handle<Object> value;
12895 {
12896 Handle<JSFunction> factory(JSFunction::cast(
12897 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12898 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012899 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012900 // This handle is nor shared, nor used later, so it's safe.
12901 Object** argv[] = { key_handle.location() };
12902 bool pending_exception = false;
12903 value = Execution::Call(factory,
12904 receiver,
12905 1,
12906 argv,
12907 &pending_exception);
12908 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012909 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012910
12911#ifdef DEBUG
12912 cache_handle->JSFunctionResultCacheVerify();
12913#endif
12914
12915 // Function invocation may have cleared the cache. Reread all the data.
12916 finger_index = cache_handle->finger_index();
12917 size = cache_handle->size();
12918
12919 // If we have spare room, put new data into it, otherwise evict post finger
12920 // entry which is likely to be the least recently used.
12921 int index = -1;
12922 if (size < cache_handle->length()) {
12923 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12924 index = size;
12925 } else {
12926 index = finger_index + JSFunctionResultCache::kEntrySize;
12927 if (index == cache_handle->length()) {
12928 index = JSFunctionResultCache::kEntriesIndex;
12929 }
12930 }
12931
12932 ASSERT(index % 2 == 0);
12933 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12934 ASSERT(index < cache_handle->length());
12935
12936 cache_handle->set(index, *key_handle);
12937 cache_handle->set(index + 1, *value);
12938 cache_handle->set_finger_index(index);
12939
12940#ifdef DEBUG
12941 cache_handle->JSFunctionResultCacheVerify();
12942#endif
12943
12944 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012945}
12946
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012948RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012950 CONVERT_ARG_CHECKED(String, type, 0);
12951 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012952 return *isolate->factory()->NewJSMessageObject(
12953 type,
12954 arguments,
12955 0,
12956 0,
12957 isolate->factory()->undefined_value(),
12958 isolate->factory()->undefined_value(),
12959 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012960}
12961
12962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012963RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012964 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12965 return message->type();
12966}
12967
12968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012969RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012970 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12971 return message->arguments();
12972}
12973
12974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012975RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012976 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12977 return Smi::FromInt(message->start_position());
12978}
12979
12980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012981RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012982 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12983 return message->script();
12984}
12985
12986
kasper.lund44510672008-07-25 07:37:58 +000012987#ifdef DEBUG
12988// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12989// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012990RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012991 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012992 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012993#define COUNT_ENTRY(Name, argc, ressize) + 1
12994 int entry_count = 0
12995 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12996 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12997 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12998#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012999 Factory* factory = isolate->factory();
13000 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013001 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013002 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013003#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013004 { \
13005 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013006 Handle<String> name; \
13007 /* Inline runtime functions have an underscore in front of the name. */ \
13008 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013009 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013010 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13011 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013012 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013013 Vector<const char>(#Name, StrLength(#Name))); \
13014 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013015 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013016 pair_elements->set(0, *name); \
13017 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013018 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013019 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013020 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013021 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013022 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013023 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013024 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013025 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013026#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013027 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013028 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013029 return *result;
13030}
kasper.lund44510672008-07-25 07:37:58 +000013031#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013032
13033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013034RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013035 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013036 CONVERT_CHECKED(String, format, args[0]);
13037 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013038 String::FlatContent format_content = format->GetFlatContent();
13039 RUNTIME_ASSERT(format_content.IsAscii());
13040 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013041 LOGGER->LogRuntime(chars, elms);
13042 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013043}
13044
13045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013046RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013047 UNREACHABLE(); // implemented as macro in the parser
13048 return NULL;
13049}
13050
13051
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013052#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13053 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13054 CONVERT_CHECKED(JSObject, obj, args[0]); \
13055 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13056 }
13057
13058ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13059ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13060ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13061ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13062ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13063ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13064ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13065ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13066ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13067ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13068ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13069ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13070ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13071
13072#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13073
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013074// ----------------------------------------------------------------------------
13075// Implementation of Runtime
13076
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013077#define F(name, number_of_args, result_size) \
13078 { Runtime::k##name, Runtime::RUNTIME, #name, \
13079 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013080
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013081
13082#define I(name, number_of_args, result_size) \
13083 { Runtime::kInline##name, Runtime::INLINE, \
13084 "_" #name, NULL, number_of_args, result_size },
13085
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013086static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013087 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013088 INLINE_FUNCTION_LIST(I)
13089 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013090};
13091
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013093MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13094 Object* dictionary) {
13095 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013096 ASSERT(dictionary != NULL);
13097 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13098 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013099 Object* name_symbol;
13100 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013101 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013102 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13103 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013104 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013105 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13106 String::cast(name_symbol),
13107 Smi::FromInt(i),
13108 PropertyDetails(NONE, NORMAL));
13109 if (!maybe_dictionary->ToObject(&dictionary)) {
13110 // Non-recoverable failure. Calling code must restart heap
13111 // initialization.
13112 return maybe_dictionary;
13113 }
13114 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013115 }
13116 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013117}
13118
13119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013120const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13121 Heap* heap = name->GetHeap();
13122 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013123 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013124 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013125 int function_index = Smi::cast(smi_index)->value();
13126 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013127 }
13128 return NULL;
13129}
13130
13131
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013132const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013133 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13134}
13135
13136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013137void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013138 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013139 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013140 if (failure->IsRetryAfterGC()) {
13141 // Try to do a garbage collection; ignore it if it fails. The C
13142 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013143 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013144 } else {
13145 // Handle last resort GC and make sure to allow future allocations
13146 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013147 isolate->counters()->gc_last_resort_from_js()->Increment();
13148 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013149 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013150}
13151
13152
13153} } // namespace v8::internal